Skip to content

Commit 4633451

Browse files
committed
feat(element binder): Two way binding for Web Components
Closes dart-archive#1282
1 parent 65fc117 commit 4633451

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

example/web/paper.html

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,18 @@
1212
href="bower_components/paper-progress/paper-progress.html">
1313
<link rel="import"
1414
href="bower_components/paper-checkbox/paper-checkbox.html">
15+
<link rel="import"
16+
href="bower_components/paper-slider/paper-slider.html">
1517
<script type="application/dart" src="paper.dart"></script>
1618
<script src="packages/browser/dart.js"></script>
1719
<style>
1820
div { padding: 0.25em; }
21+
paper-slider { width: 40em; }
1922
</style>
2023
</head>
2124
<body>
2225
<h1>Polymer components inside a AngularDart app</h1>
23-
<h2>paper-progress</h2>
26+
<h2>Property binding: paper-progress</h2>
2427
<p>This is a simple component that doesn't generate events; the only things that is required is property binding</p>
2528
<p>The max ({{max}}) and value ({{curValue}}) properties are bound through bind-* semantics</p>
2629

@@ -37,13 +40,20 @@ <h2>paper-progress</h2>
3740
</label>
3841
</p>
3942

40-
<h2>paper-checkbox</h2>
43+
<h2>Events: paper-checkbox</h2>
4144
<p>The checkbox will generate an event every time the value is changed</p>
4245
<p>AngularDart can listen to these events through the on-* syntax</p>
4346

4447
<div>
4548
<paper-checkbox on-change="curValue = curValue == 5 ? 2 : curValue == 2 ? 10 : 5"></paper-checkbox>
4649
</div>
4750
<p>Every the value changes, the curValue ({{curValue}}) scope variable will update</p>
51+
52+
<h2>Two-way binding: paper-slider</h2>
53+
<p>The slide is bound to the curValue scope variable ({{curValue}})</p>
54+
55+
<div>
56+
<paper-slider min="0" bind-max="max" bind-value="curValue" pin="true"></paper-slider>
57+
</div>
4858
</body>
4959
</html>

lib/core_dom/element_binder.dart

+14-1
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,26 @@ class ElementBinder {
284284
_link(nodeInjector, scope, nodeAttrs);
285285

286286
var jsNode;
287-
bindAttrs.forEach((String prop, ast) {
287+
List bindAssignableProps = [];
288+
bindAttrs.forEach((String prop, AST ast) {
288289
if (jsNode == null) jsNode = new js.JsObject.fromBrowserObject(node);
289290
scope.watchAST(ast, (v, _) {
290291
jsNode[prop] = v;
291292
});
293+
294+
if (ast.parsedExp.isAssignable) {
295+
bindAssignableProps.add([prop, ast.parsedExp]);
296+
}
292297
});
293298

299+
if (bindAssignableProps.isNotEmpty) {
300+
node.addEventListener('change', (_) {
301+
bindAssignableProps.forEach((propAndExp) {
302+
propAndExp[1].assign(scope.context, jsNode[propAndExp[0]]);
303+
});
304+
});
305+
}
306+
294307
if (onEvents.isNotEmpty) {
295308
onEvents.forEach((event, value) {
296309
view.registerEvent(EventHandler.attrNameToEventName(event));

test/core_dom/web_components_spec.dart

+24-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,24 @@ main() {
1414
describe('WebComponent support', () {
1515
TestBed _;
1616

17-
customProp(String prop, [elt]) {
17+
/**
18+
* Returns the property [prop] as read through the JS interface.
19+
* [elt] is optional and defaults to the [TestBed]'s rootElement.
20+
*/
21+
customProp(String prop, [Element elt]) {
1822
if (elt == null) elt = _.rootElement;
1923
return (new js.JsObject.fromBrowserObject(elt))[prop];
2024
}
2125

26+
/**
27+
* Sets the property [prop] to [value] through the JS interface.
28+
* [elt] is optional and defaults to the [TestBed]'s rootElement.
29+
*/
30+
void setCustomProp(String prop, value, [Element elt]) {
31+
if (elt == null) elt = _.rootElement;
32+
(new js.JsObject.fromBrowserObject(_.rootElement))[prop] = value;
33+
}
34+
2235
beforeEach((TestBed tb) {
2336
_ = tb;
2437
});
@@ -58,5 +71,15 @@ main() {
5871
expect(customProp('ng-bind')).toEqual("hello");
5972
expect(_.rootElement).toHaveText('hello');
6073
});
74+
75+
it('should support two-way bindings for components that trigger a change event', () {
76+
registerElement('tests-twoway', {});
77+
_.compile('<tests-twoway bind-prop="x"></tests-twoway>');
78+
79+
setCustomProp('prop', 6);
80+
_.rootElement.dispatchEvent(new Event.eventType('CustomEvent', 'change'));
81+
82+
expect(_.rootScope.context['x']).toEqual(6);
83+
});
6184
});
6285
}

0 commit comments

Comments
 (0)