Dart Polymer 1.0 - Two-way binding works? - dart

Two-way binding works in Dart Polymer 1.0 - RC2?
When I change the field #Property(nofity: true) in the .dart, it does not reflect (change) into {{}} in the .html.
See the following example.
Whem I click on paper-button, it´s fire clicar, the property text is changed, but {{text}} does not change!
main_app.html
<dom-module id="main-app">
<style>
:host {
display: block;
}
</style>
<template>
<paper-input label="Type something..." value="{{text}}"></paper-input>
<p>
Text: <span>{{text}}</span><br />
</p>
<paper-button on-click="clicar">cliqueme</paper-button>
</p>
</template>
</dom-module>
main_app.dart
#HtmlImport('main_app.html')
library untitled8.lib.main_app;
import 'dart:html';
import 'package:polymer_elements/paper_button.dart';
import 'package:polymer_elements/paper_input.dart';
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
#Property(notify: true)
String text;
MainApp.created() : super.created();
#reflectable
void clicar(e, detail) {
text = "super teste";
}
}

You need to use the provided methods to updated properties like
set('text', "super teste");
notify: true is only to notify parent elements (fires an test-changed event)
There are quite a lot such methods in PolymerBase mixin which you get automatically added by extending PolymerElement and which notify Polymer about changes.
notifyPath (currently the same as set)
for collections there are
add
addAll
clear
fillRange
insert
insertAll
removeItem
removeAt
removeLast
removeRange
removeWhere
replaceRange
retainWhere
setAll
setRange
there is also a
get
not sure about what to use it for.

Related

Auto convert html string to element

Say I have a polymer-element <polymer-element> <div id="foo"> {{html}} </div> </polymer-element>, where html is supposed to be a HTML formated string, like <p>blah</p>, what I want is, when html changes, the polymer-element also changes, and use html as its innerHtml, i.e. auto convert the string to an element and insert it as foo's child.
Can polymer/polymer_expression do this for me, or I have to do a querySelector(), then set html as innerHtml manually?
My solution is a custom element that extends a div and uses the DocumentFragment class to parse HTML strings into the DOM via data binding.
From my Github gist
<!-- Polymer Dart element that allows HTML to be inserted into the DOM via data binding -->
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="html-display" extends="div">
<script type="application/dart">
import 'dart:html';
import 'package:polymer/polymer.dart';
#CustomTag('html-display')
class HtmlDisplay extends DivElement with Polymer, Observable {
#published String htmlContent;
// we need this stuff because we're extending <div> instead of PolymerElement
factory HtmlDisplay() => new Element.tag('div', 'html-display');
HtmlDisplay.created() : super.created() {
polymerCreated();
}
#override void attached() {
super.attached();
}
// respond to any change in the "htmlContent" attribute
void htmlContentChanged(oldValue) {
if (htmlContent == null) {
htmlContent = "";
}
// creating a DocumentFragment allows for HTML parsing
this.nodes..clear()..add(new DocumentFragment.html("$htmlContent"));
}
}
</script>
</polymer-element>
<!--
Once you've imported the Polymer element's HTML file, you can use it from another Polymer element like so:
<link rel="import" href="html_display.html">
<div is="html-display" htmlContent="{{htmlString}}"></div>
*htmlString* can be something like "I <em>love</em> Polymer Dart!"
-->
I use solution as described in https://stackoverflow.com/a/20869025/789338.
The key class is DocumentFragment.
The official way to do it is described in the doc: https://www.polymer-project.org/docs/polymer/databinding-advanced.html#boundhtml
The example on the doc:
<polymer-element name="my-element">
<template>
<div id="message_area"></div>
</template>
<script>
Polymer({
message: 'hi there',
ready: function() {
this.injectBoundHTML('<b>{{message}}</b>', this.$.message_area);
}
});
</script>
</polymer-element>

Polymer Dart core-style ref not resolved

When I pass parameters to a Polymer element the core-style ref does not get resolved.
Here is the child code:
<link rel="import" href="packages/polymer/polymer.html">
<link rel="import" href="packages/core_elements/core_style.html">
<core-style id="s1" unresolved> div { background: yellow; } </core-style>
<core-style id="s2" unresolved> div { background: pink; } </core-style>
<polymer-element name='test-cell' attributes='s t' noscript>
<template>
<core-style ref="{{s}}"></core-style>
<div>{{t}}</div>
</template>
</polymer-element>
As you can see, there are two core styles.
Here is the parent code. It takes a List and instantiates 'test-cell' with text and a style reference.
<polymer-element name='test-rows'>
<template>
<template repeat='{{ v in x }}'>
<test-cell s={{v.s}} t={{v.t}}></test-cell>
</template>
</template>
</polymer-element>
In this simple example the Dart code is inline. Here it is:
<script type='application/dart'>
import 'package:polymer/polymer.dart';
//======================================
class Info {
String s, t;
Info(this.s, this.t) {}
}
//======================================
#CustomTag('test-rows')
class TestRows extends PolymerElement {
#observable List<Info> x = toObservable([]);
//-----------------------------------
TestRows.created() : super.created() {
x.add(toObservable(new Info('s1', 'first' )));
x.add(toObservable(new Info('s2', 'second')));
}
}
</script>
In the generated HTML the text comes through OK but the core-style instances both have
ref="{{s}}"
and the styles are not applied. Can I force resolution of the style ref parameter by some alternative annotation? It is essentially a final/const.
Update
I think the problem is your noscript in your test-cell element.
Binding doesn't work in Dart with Polymer elements without a backing script (noscript) as far as I know.
I think in your case the <test-cell> element needs a field
#observable
var s;
to make this work.
Original
Your code doesn't show if you ever assign a value to s.
I doubt toObservable works on plain Dart objects. This is for lists and maps as far as I know.
The Info class should look like this and you don't need to use toObservable() with it.
class Info extends Object with Observable {
#observable
String s;
#observable
String t;
Info(this.s, this.t) {}
}

How to embed the handsontable widget into a polymer-dart webcomponent

I try to embed the jquery based handsonetable (http://handsontable.com) ui widget into a polymer-dart webcomponent.
The Webcomponent is defined like that:
<polymer-element name="my-table">
<template>
<div id="table"></div>
</template>
<script type="application/dart" src="t.dart"></script>
</polymer-element>
The t.dart:
import 'package:polymer/polymer.dart';
import 'dart:js';
var data = [
["", "VW", "BMW", "Mercedes", "Mini", "Mitsubishi"],
["2012", 2, 2422, 5399, 776, 4151]
];
#CustomTag('my-table')
class MyTable extends PolymerElement
{ MyTable.created() : super.created()
{ final element = shadowRoot.querySelector("#table");
context.callMethod(r'$', [element])
.callMethod( 'handsontable', [new JsObject.jsify({'data': data,
'minSpareRows': 1,
'colHeaders': true,
'contextMenu': true})]);
}
}
I get no error, but the component isn´t initialized.
If I try in the main.dart, it works fine.
The approach works for the jquery-ui widget "datepicker" How to embed a jquery ui widget into a polymer-dart webcomponent
It doesn't look related to dart-to-js interop.
I can make the example provided on the home of http://handsontable.com/ work with dart:js but not inside a polymer element. I suspect that handsontable does not work very well with shadowDOM.

How do I fire a custom event from Polymer Dart?

I want to fire/send/emit a custom event from inside a Polymer element. For example, I want to convert a normal DOM event like "changed" to a more semantic event like "todoupdated".
This is the HTML that I have:
<polymer-element name="todo-item" extends="li" attributes="item">
<template>
<style>
label.done {
color: gray;
text-decoration: line-through;
}
</style>
<label class="checkbox {{item.doneClass}}">
<input type="checkbox" checked="{{item.done}}">
{{item.text}}
</label>
</template>
<script type="application/dart" src="todo_item.dart"></script>
</polymer-element>
I want the change events on checkbox to bubble out of the custom element as something more... useful. :)
Step 1
Capture the change events on the <input>. Notice the on-change below.
<!-- from inside todo_item.html -->
<input type="checkbox" checked="{{item.done}}" on-change="{{change}}">
Step 2
Handle the change event in the custom element code that contains the checkbox.
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'models.dart';
#CustomTag('todo-item')
class TodoItemElement extends PolymerElement with ObservableMixin {
#observable Item item;
bool get applyAuthorStyles => true;
void change(Event e, var details, Node target) {
// do stuff here
}
}
Notice the change event handler. That method is run any time the checkbox state changes.
Step 3
Dispatch a custom event.
void change(Event e, var details, Node target) {
dispatchEvent(new CustomEvent('todochange'));
}
NOTE: the custom event name must not contain dashes.
Step 4
Listen for the custom event in a parent custom element.
<template repeat="{{item in items}}" >
<li is="todo-item" class="{{item.doneClass}}" item="{{item}}" on-todochange="todoChanged"></li>
</template>
Notice the use of on-todochange.
Enjoy!
Polymer has a helper method that simplifies firing events
// dispatch a custom event
this.fire('polymer-select', detail: {'item': item, 'isSelected': isSelected});
Additional info:
To make the event available to subscriber that want to add a listener programmatically
// getter
async.Stream<dom.CustomEvent> get onPolymerSelect =>
PolymerSelection._onPolymerSelect.forTarget(this);
// private EventStreamProvider
static const dom.EventStreamProvider<dom.CustomEvent> _onPolymerSelect =
const dom.EventStreamProvider<dom.CustomEvent>('polymer-select');
subscribe to the event programmatically instead of declaratively:
($['#ps'] as PolymerSelect) // get the children and cast it to its actual type
.onPolymerSelect.listen((e) => print(e['isSelected'])); // subscribe
I managed this using <core-signals> and the polymer helper method fire. This way you are able to listen to events fired from elements that are not children. source.
todochange.html
<!doctype html>
<polymer-element name="todo-item" extends="li">
<template>
<style>
label.done {
color: gray;
text-decoration: line-through;
}
</style>
<label class="checkbox {{item.doneClass}}">
<input type="checkbox" checked="{{item.done}}">
{{item.text}}
</label>
</template>
<script type="application/dart" src="todo_item.dart"></script>
</polymer-element>
todochange.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('todo-item')
class TodoItemElement extends PolymerElement {
#observable Item item;
void change(Event e, var details, Node target) {
// the name is the name of your custom event
this.fire( "core-signal", detail: { "name": "todochange" } );
}
}
Then any subscriber just has to do this
subscriber.html
...
<link rel="import" href="packages/core_elements/core_signals.html>
...
<template>
<core-signals on-core-signal-todochange="{{handleToDoChange}}"></core-signals>
...
</template>
subscriber.dart
#CustomTag( "subscriber" )
class Sub extends PolymerElement {
...
void handleToDoChange( Event e, var detail, Node target ) {
print( "Got event from <todo-item>" );
}
...
}

Using Select Element in polymer dart component

Trying to use Select component in custom element as follows. button click works but when an item is selected in the list, the 'selected' and 'value' attribute does not change and list always shows the first element selected. Binding seems to work from dart to html but not from html to dart. Help please!
<html>
<head>
<title>index</title>
<script src="packages/polymer/boot.js"></script>
</head>
<body>
<polymer-element name="my-element" extends="div">
<template >
<button on-click='bclick'>Add new fruit</button>
<select selectedIndex="{{selected}}" value="{{value}}">
<option template repeat="{{fruit in fruits}}">{{fruit}}</option>
</select>
<div>
You selected option {{selected}} with value-from-list
{{fruits[selected]}} and value-from-binding {{value}}
</div>
</template>
<script type="application/dart" src="polyselect.dart"></script>
</polymer-element>
<my-element></my-element>
<script type="application/dart">main() {}</script>
</body>
</html>
Dart file is as follows:
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('my-element')
class MyElement extends PolymerElement {
#observable int selected = 1; // Make sure this is not null.
// Set it to the default selection index.
List fruits = toObservable(['apples', 'bananas', 'pears', 'cherry', 'grapes']);
#observable String value = '';
void bclick(Event e) {
fruits.add("passion fruit");
}
}
I had to mixin the ObservableMixin class.
class MyElement extends PolymerElement with ObservableMixin

Resources