Observing internal model attributes with Dart Polymer - dart

I'm setting up custom Polymer elements that need to display data from the model (Property objects that need to be passed around).
I can successfully display the values of the properties, but when I update a value inside a Property object, the value is not updated inside the element.
What am I missing? I based myself on the following examples:
https://github.com/sethladd/dart-polymer-dart-examples/tree/master/web/bind_component_field_to_model_field
https://github.com/sethladd/dart-polymer-dart-examples/tree/master/web/getter_setter_as_attribute
wb-control-text.html
<polymer-element name="wb-control-text">
<template>
<div>
<label for="{{id}}">{{label}}</label>
<input type="text" id="{{id}}" value="{{value}}" />
<button on-click="{{updateValue}}">Update me</button>
</div>
</template>
<script type="application/dart" src="wb-control-text.dart"></script>
</polymer-element>
wb-control-text.dart
import "package:polymer/polymer.dart";
import "package:rqn_workbench/wb-property.dart";
#CustomTag("wb-control-text")
class WorkbenchControlTextElement extends PolymerElement {
final TextProperty _idProperty = new TextProperty("id", value: "1");
final TextProperty _valueProperty = new TextProperty("value", value:"Bla");
final TextProperty _labelProperty = new TextProperty("label", value:"Label!");
WorkbenchControlTextElement.created() : super.created();
#published String get id => _idProperty.value;
void set id(String id) { _idProperty.value = id; }
#published String get value => _valueProperty.value;
void set value(String value) { _valueProperty.value = value; }
#published String get label => _labelProperty.value;
void set label(String label) { _labelProperty.value = label; }
void updateValue() {
value += "Bla";
print(value); // Will print the appended value
}
}
wb-property.dart
library workbench_property;
import "package:polymer/polymer.dart";
#observable
class Property {
String key;
}
#observable
class TextProperty extends Property {
String value;
TextProperty ( String key, {String value} ) {
this.key = key;
this.value = value;
}
}

The solution was to use #reflectable on the getters and setters, so it could be picked up by the PathObserver.

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'];
}
}

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 can an ObservableList<T> be sorted in Dart?

I can't seem to sort an ObservableList<T> and have the sort reflected in my Polymer element. Here's a sample element definition:
class PeopleElement extends PolymerElement {
ObservableList<Person> people = toObservable(new List<Person>());
PeopleElement.created() : super.created();
}
And here is the definition of the Person class:
class Person {
String name;
Person(this.name);
int compare(Person p) {
return name.compareTo(p.name);
}
}
Now, I want to add a sort function to the PeopleElement class:
class PeopleElement extends PolymerElement {
...
ObservableList<Person> sortByName() {
people.sort((Person a, Person b) {
a.compare(b);
}
}
}
I've also tried the above function as returning void and that didn't seem to work either. Does anything jump out as being incorrect here?
Your Person class needs to implement Comparable with the method compareTo instead of compare
library people_element;
import 'dart:async';
import 'package:polymer/polymer.dart';
class Person implements Comparable{
String name;
Person(this.name);
#override
int compareTo(Person other) {
return name.compareTo(other.name);
}
}
#CustomTag('people-element')
class PeopleElement extends PolymerElement {
var people = toObservable(new List<Person>());
PeopleElement.created() : super.created() {
print('PeopleElement');
}
#override
void enteredView() {
people.add(new Person('c'));
people.add(new Person('a'));
people.add(new Person('f'));
people.add(new Person('b'));
super.enteredView();
new Timer(new Duration(seconds: 3), () => sortByName());
}
ObservableList<Person> sortByName() {
people.sort();
}
}
<polymer-element name="people-element">
<template>
<template repeat="{{p in people}}">
<p>{{p.name}}</p>
</template>
</template>
<script type="application/dart" src="people_element.dart"></script>
</polymer-element>

How do I implement enums that are accessible to WebUI HTML templates in dart?

I would like to implement an enum:
enum Visibility = visible | hidden | collapsed
I would like to be able to set this in HTML code. There is some magic that allows the compiler to parse the string attribute value in HTML like 1 to int, true to bool, etc. Is there a way I can allow my own class to be parsable from string?
Dart doesn't yet have formal support for enums. We expect to add enums in the future: http://news.dartlang.org/2013/04/enum-proposal-for-dart.html
In the meantime, here is a common pattern to emulate enums:
class Enum {
final _value;
const Enum._internal(this._value);
toString() => 'Enum.$_value';
static const FOO = const Enum._internal('FOO');
static const BAR = const Enum._internal('BAR');
static const BAZ = const Enum._internal('BAZ');
}
Which came from How can I build an enum with Dart?
To create a Web UI custom element that has an enum field, you can use setters and getters to convert from a string (from HTML) to the enums.
Something like this should work:
import 'package:web_ui/web_ui.dart';
class Color {
final _value;
const Color._internal(this._value);
factory Color(String value) {
switch (value) {
case 'RED':
return Color.RED;
case 'BLUE':
return Color.BLUE;
case 'GREEN':
return Color.GREEN;
default:
throw 'not a color';
}
}
toString() => 'Color.$_value';
static const RED = const Color._internal('RED');
static const BLUE = const Color._internal('BLUE');
static const GREEN = const Color._internal('GREEN');
}
class PersonComponent extends WebComponent {
Color favoriteColor;
String get favColor => ((x) => x == null ? null : x._value)(favoriteColor);
void set favColor(String value) {
favoriteColor = new Color(value);
}
}
And then the HTML would be:
<html>
<body>
<element name="x-person" extends="div" constructor="PersonComponent">
<template>
<div>
Favorite Color: <select bind-value="favColor">
<option>RED</option>
<option>GREEN</option>
<option>BLUE</option>
</select>
</div>
<div>
You picked {{favoriteColor}}
</div>
</template>
<script type="application/dart" src="person_component.dart"></script>
</element>
</body>
</html>

Resources