Object binding between Angular and Polymer in Dart - dart

I'm trying to bind an object from an Angular controlled element to a Polymer element in Dart.
The object to bind:
class Person {
String name;
String surname;
Person(this.name, this.surname);
}
The polymer element template:
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="person-element">
<template>
<style>
.label {font-weight: bold;}
</style>
<p>
<span class="label">Name: </span>{{person.name}}
<span class="label">Surname: </span>{{person.surname}}
</p>
</template>
<script type="application/dart" src="person_element.dart"></script>
</polymer-element>
The polymer element code:
import 'package:polymer/polymer.dart';
import 'person.dart';
#CustomTag('person-element')
class PersonElement extends PolymerElement {
#published Person person;
PersonElement.created() : super.created();
}
In Angular I've created a controller and a module:
#Controller(
selector: '[person-container]',
publishAs: 'ctrl')
class PersonController {
List<Person> persons = [new Person('John','Smith'), new Person('Mario','Rossi')];
}
class PersonModule extends Module {
PersonModule() {
bind(PersonController);
}
}
The first solution tried is using the angular_node_bind package:
<div person-container ng-cloak>
<h2>Person elements</h2>
<div ng-repeat="person in ctrl.persons">
<div>{{person.name}}</div>
<person-element person="[[person]]"></person-element>
</div>
</div>
When I run the application in Dartium I get this error:
Exception: type 'String' is not a subtype of type 'Person' of 'value'. (http://localhost:8080/person_element.dart:6)
I've also tried to modify the attribute instantiation in the html code in this way:
<person-element person=[[person]]></person-element>
But I get the same exception.
The angular_node_bind package supports the object binding?
The second solution is using the new binding features of Angular 0.14.0 and binding the polymer element in this way:
With this solution I don't get any exception, the element is visualized but the fields are empty and the person instance null.
The complete example is here: https://github.com/fedy2/dart-angular-polymer-object-data-binding

The new version of AngularDart (0.14.0) has a support for Polymer-Dart binding (http://blog.angulardart.org).
At the moment there can be some problems with different versions:
Pub get failed, [1] Resolving dependencies... Incompatible version constraints on code_transformers

You can find examples at
https://github.com/angular/angular.dart/pull/1461/files
https://github.com/angular/angular.dart/tree/master/example/web
https://github.com/angular/angular.dart/blob/master/example/web/paper.html
https://github.com/angular/angular.dart/blob/master/example/web/paper.dart
https://github.com/angular/angular.dart/blob/master/example/web/paper_radio_group.html
https://github.com/angular/angular.dart/blob/master/example/web/paper_radio_group.dart
also have a look at the same files in the sept15-prg branch.
the new syntax seems to be like
<person-element bind-person="person"></person-element>
It is possible that the released Angular version doesn't yet support some things used by this examples.

Related

Dart data binding from a parent custom element to attributes of a child custom element

Here is a problem that cropped up today when I updated to the latest Dart libs.
The child custom element is a combo box. The parent custom element fills it with a varying list of strings.
// child HTML
<polymer-element name="bx-icombo" attributes="aLabel aList aSelected">
<template>
<div class='outr' flex layout horizontal center>
<label for='inp' flex end-justified>{{aLabel}}</label>
<!-- wait until the data is available -->
<template if='{{aList}}'>
<paper-dropdown-menu id='inp' label='aLabel' valign='top' flex start-justified >
<paper-dropdown class="dropdown">
<core-menu id='m' class="menu" selected="{{aSelected}}">
<template repeat='{{aList}}'>
<paper-item name='{{}}'>{{}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-dropdown-menu>
</template>
</div>
</template>
<script type='application/dart' src='bx_icombo.dart'></script>
</polymer-element>
//---------------------------------------------------------------
// child Dart
#CustomTag('bx-icombo')
class BxICombo extends PolymerElement {
#PublishedProperty(reflect: true) String aLabel;
#PublishedProperty(reflect: true) List<String> aList;
#PublishedProperty(reflect: true) String aSelected;
BxICombo.created() : super.created();
}
//---------------------------------------------------------------
// Parent HTML
<polymer-element name="tst-sigs">
<template>
<paper-dialog backdrop heading='Sigs' closeSelector=''>
<bx-icombo aLabel='{{selectAsignal}}'
aList='{{sigsList}}'
aSelected='{{sigsSel}}'>
</bx-icombo>
</paper-dialog>
</template>
<script type='application/dart' src='tst_sigs.dart'></script>
</polymer-element>
//---------------------------------------------------------------
// Parent Dart
#CustomTag('tst-sigs')
class TstSigs extends PolymerElement {
#observable List<String> sigsList = ['alpha', 'beta', 'gamma'];
#observable String sigsSel;
#observable String selectAsignal = 'Select a Signal';
TstSigs.created() : super.created();
}
//---------------------------------------------------------------
Dartium reports:
Attributes on bx-icombo were data bound prior to Polymer upgrading the element. This may result in incorrect binding types. (:1)
So what has to be changed? #PublishedProperty or #observable or #published or .... I admit to finding the maze of #... annotations deeply unclear.
The versions are:
Dart: 1.9.3 (STABLE)
Dartium: 39.0.2171.99
and packages:
analyzer 0.24.6 (0.25.0+1 available)
args 0.12.2+6 (0.13.0 available)
barback 0.15.2+4
browser 0.10.0+2
cli_util 0.0.1+1
code_transformers 0.2.8
collection 1.1.0
core_elements 0.7.1+2
csslib 0.12.0
dart_style 0.1.8
glob 1.0.4
html 0.12.1+1
ini 1.1.0
initialize 0.6.0+4
intl 0.12.2
js 0.3.0
logging 0.9.3 (0.10.0 available)
markdown 0.7.1+2
matcher 0.11.4+4 (0.12.0-alpha.0 available)
observe 0.13.0+2
paper_elements 0.7.1
path 1.3.5
petitparser 1.3.7
polymer 0.16.1+4
polymer_expressions 0.13.1
polymer_interop 0.1.0+2
pool 1.0.1
quiver 0.21.3
smoke 0.3.2
source_maps 0.10.0+2
source_span 1.1.2
stack_trace 1.3.1
string_scanner 0.1.3+1
template_binding 0.14.0+2
utf 0.9.0+2
watcher 0.9.5
web_components 0.11.2
when 0.2.0
which 0.1.3
yaml 2.1.2
Initially a problem with code-transformers forced code_transformers < 0.2.5 and that limited polymer to 0.16.0. It looks as if the code transformer thing has been resolved so I have removed the version constraint and polymer updated to 0.16.1. The problem remains.
The main function is
import 'package:polymer/polymer.dart';
import 'lib/bxglobs/bxGlobs.dart' as G;
void realMain() {
// empty for this test
}
void main() {
G.initGlobals();
initPolymer().then((zone) => zone.run(() {
Polymer.onReady.then((_) => realMain());
}));
}
and pubspec.yaml:
name: bxPoly
description: BX GUI
dependencies:
core_elements: any
ini: any
intl: any
js: any
markdown: any
paper_elements: any
polymer: any
code_transformers: any
transformers:
- polymer:
entry_points:
- web/test.html
This error almost always occurs because of elements getting registered in the wrong order. Specifically, a parent element being registered before a child element.
This is hard to diagnose without full access to the code, but following these two rules should ensure its not an issue:
Put each polymer-element in its own html file, and each class in its own dart library (using parts especially causes issues).
Make sure your elements import all of their dependencies.
edit
<template if='{{aList != null}}'>
<paper-dropdown-menu id='inp' label='aLabel' valign='top' flex start-justified >
<paper-dropdown class="dropdown">
<core-menu id='m' class="menu" selected="{{aSelected}}">
<template repeat='{{a in aList}}'>
<paper-item name='{{a}}'>{{a}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-dropdown-menu>
original
If you bind from the shadow DOM of an element to its class #observable is enough.
If you want to bind to attributes from outside of an element use #published.
If you want to use the value of a bound attribute for example in CSS selectors use #PublishedAttribute(reflect: true). reflect means the properties value is reflected to the DOM, otherwise it's only available for Polymer and Dart code.
I haven't seen this error message before. Maybe there is a problem with Polymer initialization. Do you have a custom main? Can you add it to your question?
class MyA extends PolymerElement {
#observable
aobservable = 'obs';
#published
apublished = 'pub';
#PublishedAttribute(reflect: true)
areflected = 'ref';
}
<polymer-element name="my-a">
<template>
<!-- doesn't work
<my-b bobservable="{{aobservable}}"></my-b> -->
<my-b bpublished="{{aobservable}}"></my-b>
<my-b breflected="{{aobservable}}"></my-b>
<!-- you can bind properties of MyA here no matter if
they are observable/published/reflected
(even when they have no annotation but they will not
be updated when the value changes)
You can bind only to published (reflected or not)
attributes of MyB
-->
</template>
</polymer-element>
class MyB extends PolymerElement {
#observable
bobservable = 'obs';
#published
bpublished = 'pub';
#PublishedAttribute(reflect: true)
breflected = 'rep';
}
<polymer-element name="my-b">
<template>
</template>
</polymer-element>
<head>
<style>
// you can only address reflected attributes here
my-a[areflected="ref"] {
backgroundColor: red;
}
</style>
</head>
<body>
<my-a></my-a>
</body>
This seems to be the solution. Based on debugging rather than knowledge, so beware..
Say your component foo.dart and foo.html refers to another component bar.dart and bar.html. For instance, the reference might be:
barEl el = document.querySelector('bar');
Obviously you import bar.dart at the top of foo.dart. You get the error described unless you also
<link rel="import" href="bar.html">
at the top of foo.html. Even though bar.html is not conventionally referenced in foo.html.

<debug target crashed> error when selecting date in <input type='date'>

I have the following simple .dart and .html files
.dart
//import 'dart:html';
import 'package:polymer/polymer.dart';
/// A Polymer `<main-app>` element.
#CustomTag('main-app')
class MainApp extends PolymerElement {
#observable DateTime today = new DateTime.now();
#observable String aDate = '';
/// Constructor used to create instance of MainApp.
MainApp.created() : super.created();
void onChangeFired() {
print(aDate);
}
}
.html
<!-- import polymer-element's definition -->
<link rel="import" href="../../packages/polymer/polymer.html">
<link rel="import" href="../../packages/paper_elements/paper_input.html">
<polymer-element name="main-app">
<template>
<style>
:host {
display: block;
}
</style>
<input type='date' value='{{aDate}}'
on-change='{{onChangeFired}}' id='time' class='margin-lb5px'>
</template>
<script type="application/dart" src="main_app.dart"></script>
</polymer-element>
Running the app in Dartium displays the calendar dropdown. However, each time I select a date, the application crasshes (exits) after printing the selected date with the following
2005-02-08 (:1)
<debug target crashed>
Nothing else is displyed in the console.
I created a new new polymer-app using Stagehand with the same result. Nothing else is there in the application.
This problem is present in the last two Dart Dev updates - I am currently using Dart 1.9.0-dev.9.1 (rev 44018) with the same result.
I am using the Dart eclipse plugin on Windows 8.1
Thanks
This is an issue in the Chrome version Dartium is built on.
Hopefully with Dart 1.15 we get the updated Dartium where this issue should be fixed.

Extending PaperDialog and calling toggle() via Dart

I'm trying to extend PaperDialog so that I can style it. I'm attempting to use method 3 from this solution, but with Dart instead of JS. Here's my component.
<link rel="import" href="packages/polymer/polymer.html">
<link rel="import" href="packages/paper_elements/paper_dialog.html">
<polymer-element name="hc-dialog" extends="paper-dialog" noscript>
<template>
<link href="hc-dialog.css" rel="stylesheet" type="text/css" />
<shadow></shadow>
</template>
</polymer-element>
The component appears to render correctly into the DOM - and I can verify that it functions correctly by adding opened="true" to the component - this renders great for example:
<hc-dialog opened="true" closeSelector="[dismissive]" transition="paper-dialog-transition-bottom">
<div layout horizontal>
<span flex></span>
<paper-button raised dismissive>Done</paper-button>
</div>
</hc-dialog>
But I don't want it auto-showing, and the issue comes when trying to find a way to call toggle() on this component via Dart. In the solution linked above (working JS Fiddle), it's called via JS:
<script>
Polymer('x-dialog-3', {
toggle: function() {
this.$.dialog3.toggle();
}
});
</script>
However if I try to achieve the same thing in dart, I'm unable to retrieve a component that has the toggle() method on it:
shadowRoot.querySelector('hc-dialog').toggle();
results in Object.noSuchMethod. Inspecting the returned object via reflection makes that clear:
var he = shadowRoot.querySelector('hc-dialog');
var cm = reflect(he).type;
while (cm != null) {
print(cm);
cm = cm.superclass;
}
gives:
ClassMirror on 'HtmlElement' (:1)
ClassMirror on 'Element' (:1)
ClassMirror on 'Node' (:1)
ClassMirror on 'EventTarget' (:1)
ClassMirror on 'NativeFieldWrapperClass2' (:1)
ClassMirror on 'Object' (:1)
==> My Dialog is not a PaperDialog/CoreOverlay, which is why I can't call toggle() on it.
What's wrong with this approach? How do I go about getting something I can call toggle() on?
Polymer.dart core- and paper-elements are just wrappers around Polymer.js elements. Extending is not supported for these kind of elements becaus a Dart class can't extend a JS class.

Reference static consts from HTML

I'd like to use a const within a Dart class and reference its value in my HTML. For example:
Dart class:
Class MyClass
{
static const String MY_VALUE = "foo";
}
HTML:
<input value="{{MyClass.MY_VALUE}}">
Can we do this?
No, as far as I know, you cannot use a static const in your template. The template expects instance methods and getters. There is however an easy workaround: define a getter that returns the value of the const, and then use that getter in your HTML.
Here is the code for the getter:
String get myValue => MY_VALUE;
And here is the use of the getter in the HTML:
<input value="{{myValue}}">
I tried it because I'm new to polymer, and I don't think you can have static final class variables published/observable, but you can have final instance variables. published/observable.
// my.dart
class MyClass
{
#observable static final String MY_VALUE="foo";
}
Doesn't work but this does.
// my.dart
class MyClass
{
#observable final String MY_VALUE="foo";
}
... the rest of my rambling answer.
then
<!-- mytemplate.html -->
<polymer-element name="my-tag" >
<!-- lowercase and minus convention for html tag names -->
<template>
<input value={{MY_VALUE}}/>
</template>
<script type="application/dart" src="my.dart"/>
</polymer-element>
then go back to my.dart , add
import 'package:polymer/polymer.dart';
import 'dart:html'; // what for ? why is there single quotes ?
#CustomTag('my-tag')
// camel case , brackets, single quotes,
class MyClass {
#observable static final int MY_VALUE="foo";
// lowercase after #, no brackets, no single quotes
}
from my reading of custom polymer elements
And then finally
<!-- index.html -->
<html>
<head>
<link rel="import" href="mytemplate.html"/>
<script type="application/dart">
export 'package:polymer/init.dart';
</script>
<script src="packages/browser/dart.js" />
</head>
<body>
<my-tag></my-tag>
</body>
</html>
Looking back , there's a lot of referencing going on.
The custom html polymer element has to link to dart code,
so inside the
<polymer-element></polymer-element>
tags there is a
<script type="application/dart" src="my.dart"/>
The dart code has to link to the custom html element , so there is a
#CustomTag('my-tag')
before the class declaration.
There is also a need to import the polymer library, and the html library,
and a need to make class static constant observable.
Maybe the #observable tag only works on objects.
I tried it , and it only worked on objects,
and it didn't compile when I used the abbreviated script tag inside my.html,
so I had to do
<script type="application/dart" src="my.dart">
</script>

Passing data to a Polymer element

When working with Web UI I could pass data to a component like this:
<my-element" name="{{someName}}"></my-element>
How do I pass data to a Polymer element?
You can pass data to a Polymer element, but there is a little bit more detail involved. Imagine the element with a single field, name:
// In element.dart.
import 'package:polymer/polymer.dart';
#CustomTag("my-element")
class MyElement extends PolymerElement with ObservableMixin {
#observable String name;
}
And here is the accompanying html:
// In element.html.
<polymer-element name='my-element' attributes="name">
<template>
<h2>{{name}}</h2>
</template>
<script type="application/dart" src="element.dart"></script>
</polymer-element>
Note the attributes="name" part. That configures things so that the element can be passed the name attribute when it is created (you can pass in multiple attributes by separating them with a comma if your element needs it).
When creating the element, wrap it in a <template> tag that is bound to the values you want to pass to it:
// In index.html.
<template id='name1' bind>
<my-element name="{{}}"></my-element>
</template>
<template id='name2' bind>
<my-element name="{{}}"></my-element>
</template>
Each <template> gets bound to a separate value (we'll get to that in a second). When creating the element, you can get that value using {{}} syntax.
The data can be bound to the template in the following manner:
// In index.dart.
void main() {
query('#name1').model ='Bob';
query('#name2').model ='Rohan';
}
This way, the first <my-element> is created with the name 'Bob', and the second <my-element> is created with the name 'Rohan'.

Resources