Databinding using Polymer-Dart and Dart objects - dart

I have a custom class called MyClass. I have a List<MyClass> testList in my custom element and want to use databinding for displaying the List's content.
MyClass:
class MyClass {
String name;
MyClass(String name) {
this.name = name;
}
}
custom_element.dart:
...
attached() {
super.attached();
var lst = new List<MyClass>();
lst.add(new MyClass('test'));
set('testList', lst);
}
...
custom_element.html:
...
<template is="dom-repeat" items="{{testList}}">
<span>{{item}}</span>
<span>{{item.name}}</span>
</template>
...
However, the output is:
<span>[object DartObject]<span>
<span><span>
<span>[object DartObject]<span>
<span><span>
Why doesn't it show the object's name? How can I access the property name? Neither item.name nor item['name'] work... It used to work on Polymer 0.5 and the corresponding Polymer-Dart version. :(

This is a bit confusing as there is no documentation out yet for the new polymer version, but all you (should) need to do is make your class extend the JsProxy class. If you are on the behaviors branch you will also need to annotate the class with #jsProxyReflectable. For instance:
// #jsProxyReflectable // only if you are on the `behaviors` branch
class MyClass extends JsProxy {
#reflectable // from >= 1.0.0-rc.2
String name;
MyClass(String name) {
this.name = name;
}
}

Related

Databinding structured object does not show any change on my polymer element

I am migrating an application to Polymer 1 from 0.5 and using Dart. I was doing okay but now I am facing some data binding issues:
I have created a polymer element that programatically inserts on its Local DOM another polymer element giving the information of a contact. The second element will get the information from the constructor and show it on the interface via data binding.
Parent dart:
#PolymerRegister('test-app')
class TestApp extends PolymerElement {
TestApp.created() : super.created();
attached() {
super.attached();
async(() {
insertTile();
});
}
void insertTile() {
String contactJSON = '{"contactId":"1", "firstName":"Lex", "surname":"Luthor"}';
Contact contact = new Contact(JSON.decode(contactJSON));
ContactTile tile = new ContactTile(contact, this);
Polymer.dom(this.root).append(tile);
}
}
Parent html:
<dom-module id="test-app">
<style>
:host {
display: block;
}
</style>
<template>
</template>
</dom-module>
Children dart:
#PolymerRegister('contact-tile')
class ContactTile extends PolymerElement {
factory ContactTile(Contact contact, Element parent) {
ContactTile tile = new Element.tag('contact-tile');
tile.contact = contact;
return tile;
}
ContactTile.created() : super.created();
#property Contact contact;
}
Children html:
<dom-module id="contact-tile">
<style>
:host {
display: block;
}
</style>
<template>
<div>{{ contact.contactId }}</div>
<div>{{ contact.firstName }}</div>
<div>{{ contact.surname }}</div>
</template>
</dom-module>
Contact class:
class Contact {
String contactId;
String firstName;
String surname;
Contact(Map map) {
contactId = map['contactId'];
firstName = map['firstName'];
surname = map['surname'];
}
}
For some reason the data binding does not show any of the attributes of the contact on the web interface after the contact is updated on the constructor. Is anybody able to help me with this? I have done this many times on Polymer 0.5 but on Polymer 1 this does not work.
Thank you very much.
==============================
SOLUTION
The problem was related to the notification not being raised on the constructor of ContactTile. I could fix this by modifying the contact using the "set" function which updates the property and notifies. There are two ways to do this:
a. #Property(notify: true)
#PolymerRegister('contact-tile')
class ContactTile extends PolymerElement {
factory ContactTile(Contact contact, Element parent) {
ContactTile tile = new Element.tag('contact-tile');
tile.contact = contact;
return tile;
}
ContactTile.created() : super.created();
#Property(notify: true)
Contact contact;
}
b. polymerElement.set("name", value);
#PolymerRegister('contact-tile')
class ContactTile extends PolymerElement {
factory ContactTile(Contact contact, Element parent) {
ContactTile tile = new Element.tag('contact-tile');
// tile.contact = contact;
tile.set("contact", contact);
return tile;
}
ContactTile.created() : super.created();
#property
Contact contact;
}
Also for accessing to the object attributes, I had to make the class to extend JsProxy and add #property to every attribute (or #reflectable for methods).
import 'package:polymer/polymer.dart';
class Contact extends JsProxy {
#property
String contactId;
#property
String firstName;
#property
String surname;
Contact(Map map) {
contactId = map['contactId'];
firstName = map['firstName'];
surname = map['surname'];
}
}
Since the Contact class isn't a full custom element, should it inherit from JsProxy and have annotations of the properties. This will make the properties accessible in html. Shown below.
class Contact extends JsProxy {
#property String contactId;
#property String firstName;
#property String surname;
Contact(Map map) {
contactId = map['contactId'];
firstName = map['firstName'];
surname = map['surname'];
}
}

Polymer Dart 1.0 - Observer not working

I have a custom element <test-object> which looks like this:
#PolymerRegister('test-object')
class TestObject extends PolymerElement with TestBehavior {
TestObject.created() : super.created() {
}
}
The TestBehavior:
#reflectable
class TestModel extends JsProxy {
#Property(notify: true)
num value = 0;
PolymerElement _target;
TestModel(PolymerElement target) {
_target = target;
}
changeBy(num by) {
value += by;
_target.set('testModel.value', value);
}
}
#behavior
abstract class TestBehavior implements PolymerBase {
#Property(notify: true)
TestModel testModel;
PolymerElement _instance;
static ready(instance) {
instance._init(instance);
}
static created(instance) {
instance._instance = instance;
}
_init(PolymerElement instance) {
set('testModel', new TestModel(instance));
}
}
My main app looks like this:
<dom-module id="main-app">
<style>
:host {
display: block;
#apply(--layout-center-center);
}
</style>
<template>
<div>{{testObject.testModel.value}}</div>
<test-object id="obj"></test-object>
</div>
</template>
</dom-module>
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
#Property(notify: true)
TestObject testObject = null;
MainApp.created() : super.created();
ready() {
set('testObject', testObject = $$('#obj') as TestObject);
}
#Listen('click')
clicked([_]) {
testObject.testModel.changeBy(1);
}
#Observe('testObject.testModel.*')
valueChanged([_]) {
window.console.log('Value was changed');
}
}
This is a very simple toy example. I click <main-app> which causes the value in testModel to increase (this works). However, <main-app> doesn't update the div which should display the value. Also, valueChanged is never invoked.
I want to notify testObject about the valueupdate in testModel and propagate this notification up to main-app which than should update its UI via data binding.
Why is this not working?
You can't have a property in model classes, only in components
#Property(notify: true)
num value = 0;
should just be
#reflectable
num value = 0;
The set and notifyPath methods should really be called from your element classes, not the models. This actually simplifies your code a lot, and makes everything work as expected as well. Below I have pasted the new MainApp, TestModel, and TestBehavior classes (I also made some other minor edits).
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
// Defines a read-only property (implicit because of the getter).
#property
TestObject get testObject => $['obj'];
MainApp.created() : super.created();
// I added the 2nd optional argument here, to fix a reflectable error
#Listen('click')
clicked([_, __]) {
// Notify directly here, this is the primary change.
notifyPath('testObject.testModel.value', testObject.testModel.changeBy(1));
}
#Observe('testObject.testModel.*')
valueChanged([_]) {
window.console.log('Value was changed');
}
}
// Removed the `_instance` field.
class TestModel extends JsProxy {
// use #reflectable instead of #Property(notify: true)
#reflectable
num value = 0;
TestModel();
num changeBy(num by) {
value += by;
// Added a return value for convenience
return value;
}
}
#behavior
abstract class TestBehavior implements PolymerBase {
#Property(notify: true)
TestModel testModel = new TestModel();
}

Published Getter and Setter in Dart [duplicate]

I am trying to understand how observable getters work when they use other class instance properties:
When I bind the implicit getter/setter pair 'name' it updates in the input and in the div and everything is synced nicely.
However the explicit getter 'fullname' is not updating in the HTML. Is there a way to make that work (basically the 'fullname' in the element binding should update as well)?? Maybe I am missing a setter, but then again setter does not make sense here...
Very simple example to demonstrate:
test-element.html
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="test-element">
<template>
<input value="{{ds.name}}">
<div>{{ds.name}}</div>
<div>{{ds.fullname}}</div>
</template>
<script type="application/dart" src="test1.dart"></script>
</polymer-element>
test-element.dart
import 'package:polymer/polymer.dart';
import 'package:popoli/sysmaster-settings.dart';
#CustomTag('test-element')
class TestElement extends PolymerElement {
#observable VerySimpleTest ds;
TestElement.created() : super.created() {
ds = new VerySimpleTest()..name = 'Peter';
}
}
ds.dart
class VerySimpleTest extends Observable {
#observable String name = '';
#observable String get fullname => 'Test: $name';
VerySimpleTest() : super();
}
You need to notify Polymer that a value has changed the getter depends on.
String set name(String val) {
name = notifyPropertyChange(#fullname, name, val);
}
or this should work too
#ComputedProperty('Test: $name') String get fullname => 'Test: $name';
See http://japhr.blogspot.co.at/2014/08/the-polymerdart-computedproperty.html for more details.
Some minor adaptations on Günter’s proposal make it work for me:
class VerySimpleTest extends Observable {
String _name = '';
// #observable // apparently, not even required
String get name => _name;
// #observable // apparently, not even required
String get fullname => 'Test: $name';
set name(String val) {
String oldVal = _name;
_name = notifyPropertyChange(#name, oldVal, val);
_name = notifyPropertyChange(#fullname, oldVal, val);
}
}

Dart: #observable of getters

I am trying to understand how observable getters work when they use other class instance properties:
When I bind the implicit getter/setter pair 'name' it updates in the input and in the div and everything is synced nicely.
However the explicit getter 'fullname' is not updating in the HTML. Is there a way to make that work (basically the 'fullname' in the element binding should update as well)?? Maybe I am missing a setter, but then again setter does not make sense here...
Very simple example to demonstrate:
test-element.html
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="test-element">
<template>
<input value="{{ds.name}}">
<div>{{ds.name}}</div>
<div>{{ds.fullname}}</div>
</template>
<script type="application/dart" src="test1.dart"></script>
</polymer-element>
test-element.dart
import 'package:polymer/polymer.dart';
import 'package:popoli/sysmaster-settings.dart';
#CustomTag('test-element')
class TestElement extends PolymerElement {
#observable VerySimpleTest ds;
TestElement.created() : super.created() {
ds = new VerySimpleTest()..name = 'Peter';
}
}
ds.dart
class VerySimpleTest extends Observable {
#observable String name = '';
#observable String get fullname => 'Test: $name';
VerySimpleTest() : super();
}
You need to notify Polymer that a value has changed the getter depends on.
String set name(String val) {
name = notifyPropertyChange(#fullname, name, val);
}
or this should work too
#ComputedProperty('Test: $name') String get fullname => 'Test: $name';
See http://japhr.blogspot.co.at/2014/08/the-polymerdart-computedproperty.html for more details.
Some minor adaptations on Günter’s proposal make it work for me:
class VerySimpleTest extends Observable {
String _name = '';
// #observable // apparently, not even required
String get name => _name;
// #observable // apparently, not even required
String get fullname => 'Test: $name';
set name(String val) {
String oldVal = _name;
_name = notifyPropertyChange(#name, oldVal, val);
_name = notifyPropertyChange(#fullname, oldVal, val);
}
}

How do I add a valid default constructor to a dart polymer class?

The following code defines the Polymer element
What do I need as a valid default constructor for this class?
My question is what is needed for a proper constructor
import 'package:polymer/polymer.dart';
import 'lib/NPIDefs.dart';
import 'dart:html';
/**
* A Polymer click counter element.
*/
#CustomTag('detail-panel')
class NPIDetailPanel extends PolymerElement {
#published #observable NPIRecord record;
#observable String detailPanelICON = "unfold-less";
NPIDetailPanel.created() : super.created() {
}
setValue(NPIRecord npiRec) {
record = npiRec;
}
void dremoveDetailPanel() {
Element e;
e = shadowRoot.querySelector('#dpanel');
if(e != null) {
e.remove();
}
}
The code below gets a The class 'NPIDetailPanel' does not have a default constructor error
Please show how to do a default constructor
in the definition of the class
void addDetailPanel(Event e) {
NPIDetailPanel e1;
e1 = new NPIDetailPanel();
}
/* How do I add a proper default constructor? */
You can create a new instance of a Polymer element using new Element.tag('some-tag');
Just add a factory constructor that contains this to your Polymer element class.
#CustomTag('detail-panel')
class NPIDetailPanel extends PolymerElement {
factory NPIDetailPanel NPIDetailPanel() => new Element.tag('detail-panel'); // <== added
#published #observable NPIRecord record;
#observable String detailPanelICON = "unfold-less";
NPIDetailPanel.created() : super.created() {
}
setValue(NPIRecord npiRec) {
record = npiRec;
}
void dremoveDetailPanel() {
Element e;
e = shadowRoot.querySelector('#dpanel');
if(e != null) {
e.remove();
}
}
}
see also Instantiating polymer element via dart code

Resources