Getting error converting dart2js on polymer project - dart

Unsupported operation: Can't use ownerName in reflection because it is not included in a #MirrorsUsed annotation.
ownerName is just an published attribute on the polymer element. I understand there are a few things out there (on web, not on here) like this but none have a solid answer...
I also get this below it:
NoSuchMethodError : method not found: 'Symbol("title")'
Anyone got any ideas. Been wrestling with this for 3 hours and ready to dump polymer. Though It was fun in dartium, if it cannot convert to JS I see no real use in it.
import 'package:polymer/polymer.dart';
import 'package:google_postendpoint_v1_api/postendpoint_v1_api_browser.dart';
import 'package:google_postendpoint_v1_api/postendpoint_v1_api_client.dart';
import 'dart:math';
//import 'package:intl/intl.dart';
/**
* A Polymer post element.
*/
#CustomTag('post-element')
class SoberSky extends PolymerElement {
#published int count = 0;
#published String ownerName = "Casey";
#published int ownerId = 888;
#published int postId = 333;
#published String content = "yo ho ho, and a bottle of rumsky!";
#published String postContent = "This is an example of post content";
#published int getOwnerId = 333;
#published CollectionResponse_Comment listComment;
#published CollectionResponse_Post listPost;
#published String listCommentHTML;
#published Post currentPost;
#published bool yes = false;
Postendpoint endpoint = new Postendpoint();
var rng = new Random();
var commentList;
SoberSky.created() : super.created() {
endpoint.rootUrl = "http://localhost:8888/"; // set the root URL
}
void getListComment([int tempPostId]) {
if (tempPostId == null) {
tempPostId = postId;
}
endpoint.listComment( tempPostId ).then((CollectionResponse_Comment commentCollection){
this.listComment = commentCollection;
}).catchError((e) => handleError(e));
}
void getPost() {
endpoint.getPost( postId ).then((Post loadedMessage) {
currentPost = loadedMessage;
getListComment(currentPost.key);
}).catchError((e) => handleError(e));
}
void submitComment() {
int id = rng.nextInt(1000);
Comment comment = new Comment.fromJson({});
comment.id = id;
comment.content = content;
comment.postId = postId;
comment.ownerName = ownerName;
comment.ownerId = ownerId;
endpoint.insertComment( comment ).then((Comment savedComment) => endpoint.getComment(id)).
then((Comment loadedMessage) {
print(loadedMessage.content);
getListComment(loadedMessage.postId);
}).catchError((e) => handleError(e));
}
void submitPost(){
postId = rng.nextInt(1000);
Post post = new Post.fromJson({});
post.key = postId;
post.ownerName = ownerName;
post.ownerId = ownerId;
post.title = postContent;
endpoint.insertPost( post ).then((Post savedPost) => endpoint.getPost(postId)).
then((Post loadedMessage) {
print(loadedMessage.title);
getPost();
getListComment(loadedMessage.key);
}).catchError((e) => handleError(e));
}
void handleError(Error e) {
print("We had an error: ");
print(e.toString());
}
#override
void attached() {
}
}
The HTML Polymer element
<polymer-element name="click-counter" attributes="count">
<template>
<form action="javascript:void(0);" >
<div class="entry">
<label>Enter Post:</label>
<input id="subject" type="text" value="{{postContent}}" size="45" maxlength="255">
<button on-click="{{submitPost}}" class="btn btn-success" >Submit Post</button> <br>
</div>
</form>
<div class="post">
<h3>{{ currentPost.ownerName }}</h3>
<p>{{ currentPost.title }}</p>
<p>This is the postId: {{ currentPost.key }}</p>
<p class="timestamp">{{ currentPost.uploadTime }}</p>
<template repeat="{{comment in listComment.items}}">
<div class="comment">
<h3>{{ comment.ownerName }}</h3>
<p>{{ comment.content }}</p>
<p>This is the commentId: {{ comment.id }}</p>
<p class="timestamp">{{ comment.formatDate }}</p>
</div>
</template>
<form action="javascript:void(0);">
<label>Enter Comment:</label>
<input id="subject" type="text" value="{{content}}" size="45" maxlength="255">
<button on-click="{{submitComment}}" class="btn btn-success">Submit Comment</button> <br>
</form>
</div>
</template>
<script type="application/dart" src="clickcounter.dart"></script>
</polymer-element>

I have not yet seen your Unsupported operation message. Maybe some recent change. Your NoSuchMethodError is common when a property of a class is only referenced by a polymer expression (HTML) because tree-shaking drops all code that is not referenced and polymer expressions are not evaluated for this yet. The #MirrorsUsed annotation helps bridging this gap.
The problem is in your Post class because it's properties are only referenced in polymer expressions
<div class="post">
<h3>{{ currentPost.ownerName }}</h3>
<p>{{ currentPost.title }}</p>
<p>This is the postId: {{ currentPost.key }}</p>
<p class="timestamp">{{ currentPost.uploadTime }}</p>
To get your view updated when the properties in your currentPost change you should make your Post class like
class Post extends Object with Observable {
#observable String ownerName;
#observable String title;
...
}
If you have an annotation like #reflectable, #published, or #observable you don't need #MirrorsUsed.

Related

How to get additionalData of RouteDefinition inside of a html template in Dart

I'm trying to define the page name of a route inside the var additionalData, but I don't know how to get this value inside the html template.
static final unidadeFederativa = RouteDefinition(
routePath: RoutePaths.unidadeFederativa,
component: unidade_federativa_list_template.UnidadeFederativaListComponentNgFactory,
additionalData: { "pageName": "Unidade Federativa"}
);
<material-content>
<header class="material-header shadow">
<div class="material-header-row">
<material-button icon class="material-drawer-button" (trigger)="drawer.toggle()">
<material-icon icon="menu"></material-icon>
</material-button>
<span class="material-header-title">{{pageName}}}</span>
<div class="material-spacer"></div>
</div>
</header>
<div class="app-content">
<router-outlet [routes]="Routes.all"></router-outlet>
</div>
</material-content>
In order to access the additionalData you passed in the route definition, you have to retrieve it in the component first.
routes.dart :
static final all = <RouteDefinition>[
home,
RouteDefinition(
path: '.+',
component: not_found_template.NotFoundComponentNgFactory,
additionalData:{ "status": "404", "error": "Not Found" }
),
];
not_found_component.dart
class NotFoundComponent implements OnActivate {
final Router _router;
NotFoundComponent(this._router);
var status;
#override
void onActivate(RouterState previous, RouterState current) {
// To retrieve normal queryParams :
// var queryParams = current.queryParameters;
// To retrieve the additional data you posted (check if exists)
this.status = current.routePath.additionalData.status;
}
}
You can then display the data in your component's template :
<div>
<h1>{{status}}</h1>
</div>

knockout array radio button and/or droplist based

Right now I am populating radio button from the observable array,
<div data-bind="foreach: cars">
<div>
<input type='radio' data-bind="checked: $root.vehicle, checkedValue: id, value:id"><span data-bind="text: model"></span>
</div>
</div>
Model data,
public class MyViewModel
{
public List<Cars> cars {get; set;}
}
public class Cars
{
public int Id{get; set;}
public string Make {get; set;}
public string Model {get; set;}
}
Say if I want to populated radio button for Make 'Honda' and dropdown list for make 'Toyota'. How to do that?
Basically, I am trying populate two different list of controls from same observable array.
If I understand what exactly you want to do, here is an example through what you could do :
Example :https://jsfiddle.net/kyr6w2x3/85/
HTML :
<div data-bind="foreach: Cars">
<input type='radio' data-bind="checked :$parent.VehicleSelected ,checkedValue: Make, value:Id">
<span data-bind="text: Make"></span>
<select data-bind="foreach:Models,visible:IsSelected" >
<option data-bind="text:Name , value:Id"></option>
</select>
<br />
</div>
JS:
var data = [
{Id:1,Make :"TOYOTA",Model: [{Id:1,Name:"COROLLA"},{Id:2,Name:"CAMERY"},{Id:3,Name:"PERADO"}]},
{Id:2,Make :"HONDA",Model:[{Id:4,Name:"CIVIC"},{Id:5,Name:"ACCORD"},{Id:6,Name:"PILOT"}]},
{Id:3,Make :"NISSAN",Model:[{Id:7,Name:"SENTRA"},{Id:8,Name:"ALTIMA"},{Id:9,Name:"JUKE"}]}];
function AppViewModel() {
var self = this ;
self.Cars = ko.observableArray($.map(data, function (item) {
return new CarItemViewModel(item);
}));
self.VehicleSelected = ko.observable();
self.VehicleSelected.subscribe(function(newValue){
ko.utils.arrayForEach(self.Cars(), function(item) {
if (item.Make().toUpperCase() === newValue.toUpperCase()) {
return item.IsSelected(true);
}else{
return item.IsSelected(false);
}
});
})
}
var CarItemViewModel = function (data){
var self = this ;
self.Id = ko.observable(data.Id);
self.Make = ko.observable(data.Make);
self.Models = ko.observableArray($.map(data.Model, function (item) {
return new ModelsItemViewModel(item);
}));
self.IsSelected = ko.observable(false);
}
var ModelsItemViewModel = function (data){
var self = this ;
self.Id = data.Id;
self.Name = data.Name;
}
var appVM = new AppViewModel()
ko.applyBindings(appVM);
My interpretation of your question:
You have one variable that holds all your data
You want to render multiple UI elements that represent sub-sets of these data
A good way to do this is by using ko.computeds that return the filtered result of an observableArray. An example:
var allCars = ko.observableArray([
{"name":"CIVIC","make":"HONDA"},
{"name":"SENTRA","make":"NISSAN"}];
var hondas = ko.computed(function() {
return allCars().filter(function(car) {
return car.make === "HONDA";
});
});
Because the computed uses the allCars observable, it is notified when the source data changes. The filter method is re-evaluated. In the snippet below you can see that you can push new data to your source and is automatically put in the right subset!
var allCars = ko.observableArray([
{"name":"CIVIC","make":"HONDA"},
{"name":"ACCORD","make":"HONDA"},
{"name":"PILOT","make":"HONDA"},
{"name":"SENTRA","make":"NISSAN"},
{"name":"ALTIMA","make":"NISSAN"},
{"name":"JUKE","make":"NISSAN"}]);
var hondas = ko.computed(function() {
return allCars().filter(function(car) {
return car.make === "HONDA";
});
});
var nissans = ko.computed(function() {
return allCars().filter(function(car) {
return car.make === "NISSAN";
});
});
var otherBrands = ko.computed(function() {
return allCars().filter(function(car) {
return car.make !== "NISSAN" &&
car.make !== "HONDA";
});
});
var inputVM = {
name: ko.observable(""),
make: ko.observable(""),
add: function() {
allCars.push({
name: this.name(),
make: this.make().toUpperCase()
});
}
};
ko.applyBindings({
hondas: hondas,
nissans: nissans,
allCars: allCars,
otherBrands: otherBrands,
inputVM: inputVM
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h2>Honda</h2>
<ul data-bind="foreach: hondas">
<li data-bind="text: name"></li>
</ul>
<h2>Nissan</h2>
<ul data-bind="foreach: nissans">
<li data-bind="text: name"></li>
</ul>
<h2>Other brands</h2>
<ul data-bind="foreach: otherBrands">
<li data-bind="text: name"></li>
</ul>
<h2>Add car</h2>
<div data-bind="with: inputVM">
<label>
Name:
<input type="text" data-bind="value: name">
</label>
<label>
Make:
<input type="text" data-bind="value: make">
</label>
<button data-bind="click: add">Add</button>
</div>

Setting a hidden attribute in dart-polymer 1.x

I am trying to toggle (hide/unhide> a state dropdown menu when the USA is selected in a country dropdown menu
.html
<paper-dropdown-menu
label = "Country *"
selected-item-label = "{{countrySelectedItemLabel}}"
error-message = "Country is required"
id = "countryDdm">
<paper-menu class = "dropdown-content">
<template
is = "dom-repeat"
items = "[[countries]]"
as = "country">
<div>[[country.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
<div class = "layout horizontal">
<paper-dropdown-menu
hidden = $"[[hideState]]"
label = "State *"
selected-item-label = "{{stateSelectedItemLabel}}"
id = "stateDdm">
<paper-menu class = "dropdown-content">
<template
is = "dom-repeat"
items = "[[states]]"
as = "state">
<div>[[state.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
The relevant .dart code is shown below
##.dart
#property
bool hideState;
#property
String countrySelectedItemLabel = '';
#Listen( 'countryDdm.tap' )
void toggleStateOnUSASelection( event, [_] ) {
switch ( countrySelectedItemLabel ) {
case 'United States of America':
switch ( hideState ) {
case true:
hideState = false;
break;
case false:
break;
}
break;
}
}
void ready( ) {
set('hideState', true);
}
The application is displayed normally but when I select 'United States of America' the state combo is NOT shown. I would also like to hide the state combo if any country than the USA is selected.
Any help is appreciated. Thanks.
The $ is on the wrong position
hidden$="[[hideState]]"
The actual hidden attribute is set by Polymer. This is to work around issues with attributes like href of the <img> element where binding expressions (strings that aren't an actual URI to an image) would produce an error message before Polymer even had a chance to resolve the binding expression.
There are a few further issues (see the comments in the code)
dart
#HtmlImport('app_element.html')
library so33931432_hide_paper_dropdown.web.app_element;
import 'package:web_components/web_components.dart' show HtmlImport;
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/paper_dropdown_menu.dart';
import 'package:polymer_elements/paper_menu.dart';
/// [PaperDropdownMenu], [PaperMenu]
#PolymerRegister('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created();
#property
List<String> countries = ['Austria', 'Belgium', 'Czech Republic', 'United States of America'];
#property
bool hideState; // = true; // you could set a default value, then you don't need ready
// This way usually works better for me than #Listen
#Property(observer: 'toggleStateOnUSASelection')
String countrySelectedItemLabel = '';
// If `#Property(observer: ...) is used the function signature
// has to be changed
#reflectable
void toggleStateOnUSASelection(String label, [_]) {
switch (countrySelectedItemLabel) {
// I wasn't sure what you actually tried to accomplish here
// but this worked for me to reproduce your problem
case 'United States of America':
set('hideState', false);
break;
default:
set('hideState', true);
}
}
void ready() {
set('hideState', true);
}
}
html
<!DOCTYPE html>
<dom-module id='app-element'>
<template>
<paper-dropdown-menu
label="Country *"
selected-item-label="{{countrySelectedItemLabel}}"
error-message="Country is required"
id="countryDdm">
<paper-menu class="dropdown-content">
<template
is="dom-repeat"
items="[[countries]]"
as="country">
<div label="[[country]]">[[country]]</div>
</template>
</paper-menu>
</paper-dropdown-menu>
<div>selectedItem:<span>[[countrySelectedItemLabel]]</span> value: <span>[[countrySelectedItemLabel]]</span></div>
<div>hideState: <span>[[hideState]]</span></div>
<div class="layout horizontal">
<paper-dropdown-menu
hidden$="[[hideState]]"
label="State *"
selected-item-label="{{stateSelectedItemLabel}}"
id="stateDdm">
<paper-menu class="dropdown-content">
<template
is="dom-repeat"
items="[[states]]"
as="state">
<div>[[state.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
</div> <!-- missing in your question -->
</template>
</dom-module>

Polymer linkPaths does not fire on-change et all

EDITED: NOW WITH COMPLETE CODE
Previous Post related
LinkPaths works, but does not fire all on-change event of the elements where the data changed. See the image:
For example, when data is changed on <paper-input label="Produto" value="{{item.descricao}}"></paper-input> (outer dom-repeat) the data in element <paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input> (inner dom-repeat) change too. It´s works nice because of the linkPaths!
But on-change="mudou" does not fire.
Just fire if data entry directly on <paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input> (inner dom-repeat)
main_app.html
<dom-module id="main-app">
<style>
:host {
display: block;
}
</style>
<template>
<h3>Lista de Produtos</h3>
<template is="dom-repeat" items="{{produtos}}" as="item">
<div class="layout vertical">
<paper-material elevation="1">
<div class="layout horizontal">
<paper-input label="Produto" value="{{item.descricao}}"></paper-input>
</div>
</paper-material>
<template is="dom-repeat" items="{{item.componentes}}" as="item_comp">
<div class="layout vertical">
<div class="layout horizontal">
<paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input>
</div>
</div>
</template>
</div>
</template>
</template>
</dom-module>
main_app.dart
import 'dart:html';
import 'package:polymer_elements/paper_input.dart';
import 'package:polymer_elements/paper_fab.dart';
import 'package:polymer_elements/iron_icons.dart';
import 'package:polymer_elements/paper_material.dart';
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
#Property(notify: true)
List<Produto> produtos = new List();
MainApp.created() : super.created();
void ready() {
Produto p = new Produto()..descricao = 'componente 1';
add('produtos', p);
Produto p2 = new Produto()..descricao = 'componente 2';
add('produtos', p2);
Produto p3 = new Produto()..descricao = 'composto';
add('produtos', p3);
add('produtos.2.componentes', p);
add('produtos.2.componentes', p2);
linkPaths('produtos.2.componentes.0', 'produtos.#0');
linkPaths('produtos.2.componentes.1', 'produtos.#1');
linkPaths('produtos.0', 'produtos.#2.componentes.#0');
linkPaths('produtos.1', 'produtos.#2.componentes.#1');
}
#reflectable
void adicionarProduto(e, d) {
//...
}
#reflectable
mudou(e, d) {
window.alert('teste');
}
}
class Produto extends JsProxy {
#reflectable
String descricao;
#reflectable
List<Produto> componentes;
Produto() {
componentes = new List();
}
}
Is this normal in Polymer? How I can to force fire on-change?
I found a workaround solution.
I used computed binding method, no more on-change event. This form, I passed the paper-input value reference on method call, and all time that value change, the method is called.
The code changed:
.html
...
<paper-input label="Produto Componente" value="{{item_comp.descricao}}"></paper-input>
<span>{{mudou(item_comp.descricao)}}</span>
...
.dart
...
#reflectable
void mudou(a) {
window.alert('teste');
}
...

Creating a custom Polymer element

I'm trying to create a custom Polymer element that extends paper-shadow to display a Tweet.
Here is my implementation:
tweet_element.html
<link rel="import" href="packages/paper_elements/paper_shadow.html">
<link rel="import" href="packages/polymer/polymer.html">
<link rel="stylesheet" href="tweet_element.css">
<polymer-element name="tweet-element" extends="paper-shadow">
<template>
<div id="header">
<div id="user-image">
<img src="{{userImageUrl}}">
</div>
<div id="details">
<div id="user">{{user}}</div>
<div id="date-published">{{datePublished}}</div>
</div>
</div>
<div id="content">
<div id="text">{{text}}</div>
<div id="photos">{{photos}}</div>
</div>
</template>
<script type="application/dart" src="twitter.dart"></script>
</polymer-element>
twitter.dart
import 'package:polymer/polymer.dart';
#CustomTag('tweet-element')
class TweetElement extends PolymerElement {
#Observable String userImageUrl;
#Observable String user;
#Observable String datePublished;
#Observable String text;
TweetElement.created() : super.created();
void update(Tweet tweet) {
userImageUrl = tweet.user.profileImage;
user = '${tweet.user.name} (#${tweet.user.screenName})';
datePublished = _parseDate(tweet.date);
text = tweet.text;
}
...
}
And finally the code that creates a TweetElement and tries to add it to the DOM:
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'twitter.dart';
...
var mainContent = querySelector('#main-content');
var element;
for (var tweet in tweets) {
element = new TweetElement.created();
element.update(tweet);
mainContent.children.add(element);
}
And when I run this I get:
Exception: Uncaught Error: created called outside of custom element creation.
So then I tried to change twitter.dart to:
TweetElement.created() : super.created();
TweetElement (Tweet tweet) {
TweetElement.created();
userImageUrl = tweet.user.profileImage;
user = '${tweet.user.name} (#${tweet.user.screenName})';
datePublished = _parseDate(tweet.date);
text = tweet.text;
}
And add the element to the DOM like this:
var mainContent = querySelector('#main-content');
var element;
for (var tweet in tweets) {
element = new TweetElement(tweet);
mainContent.children.add(element);
}
And now I got this error:
Internal error: unresolved implicit call to super constructor 'PolymerElement()' TweetElement (Tweet tweet) {
Ralph.
You can do that in two ways:
Option A
If you want to create a Polymer Element in your Dart code, you just have to create that tag this way:
var myTweetElement = new Element.tag ('tweet-element');
mainContent.childern.add(myTweetElement);
Also, check that you have imported the html library:
import 'dart:html';
Option B: (the coolest one)
You can do it extra convenient (and more object oriented) by adding this factory to your twitter.dart:
factory TweetElement () => new Element.tag('tweet-element');
Then, the creation of the tag in your dart code, is more readable:
var myTweetElement = new TweetElement (); // This uses the factory transparently
mainContent.children.add(myTweetElement);
Additionally, you can set the values of your properties. As those are observable, the bindings will update automagically:
myTweetElement.userImageUrl = "foo"
myTweetElement.user = "bar"
myTweetElement.datePublished = "baz"
myTweetElement.text = "qux"
Or if you like the cascade operator, you can write this instead:
myTweetElement..userImageUrl = "foo"
..user = "bar"
..datePublished = "baz"
..text = "qux";
Hope this helps.

Resources