Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

Two-way binding for Web Components #1282

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions example/web/paper.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
href="bower_components/paper-progress/paper-progress.html">
<link rel="import"
href="bower_components/paper-checkbox/paper-checkbox.html">
<link rel="import"
href="bower_components/paper-slider/paper-slider.html">
<script type="application/dart" src="paper.dart"></script>
<script src="packages/browser/dart.js"></script>
<style>
div { padding: 0.25em; }
paper-slider { width: 40em; }
</style>
</head>
<body>
<h1>Polymer components inside a AngularDart app</h1>
<h2>paper-progress</h2>
<h2>Property binding: paper-progress</h2>
<p>This is a simple component that doesn't generate events; the only things that is required is property binding</p>
<p>The max ({{max}}) and value ({{curValue}}) properties are bound through bind-* semantics</p>

Expand All @@ -37,13 +40,20 @@ <h2>paper-progress</h2>
</label>
</p>

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

<div>
<paper-checkbox on-change="curValue = curValue == 5 ? 2 : curValue == 2 ? 10 : 5"></paper-checkbox>
</div>
<p>Every the value changes, the curValue ({{curValue}}) scope variable will update</p>

<h2>Two-way binding: paper-slider</h2>
<p>The slide is bound to the curValue scope variable ({{curValue}})</p>

<div>
<paper-slider min="0" bind-max="max" bind-value="curValue" pin="true"></paper-slider>
</div>
</body>
</html>
15 changes: 14 additions & 1 deletion lib/core_dom/element_binder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,26 @@ class ElementBinder {
_link(nodeInjector, scope, nodeAttrs);

var jsNode;
bindAttrs.forEach((String prop, ast) {
List bindAssignableProps = [];
bindAttrs.forEach((String prop, AST ast) {
if (jsNode == null) jsNode = new js.JsObject.fromBrowserObject(node);
scope.watchAST(ast, (v, _) {
jsNode[prop] = v;
});

if (ast.parsedExp.isAssignable) {
bindAssignableProps.add([prop, ast.parsedExp]);
}
});

if (bindAssignableProps.isNotEmpty) {
node.addEventListener('change', (_) {
bindAssignableProps.forEach((propAndExp) {
propAndExp[1].assign(scope.context, jsNode[propAndExp[0]]);
});
});
}

if (onEvents.isNotEmpty) {
onEvents.forEach((event, value) {
view.registerEvent(EventHandler.attrNameToEventName(event));
Expand Down
25 changes: 24 additions & 1 deletion test/core_dom/web_components_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@ main() {
describe('WebComponent support', () {
TestBed _;

customProp(String prop, [elt]) {
/**
* Returns the property [prop] as read through the JS interface.
* [elt] is optional and defaults to the [TestBed]'s rootElement.
*/
customProp(String prop, [Element elt]) {
if (elt == null) elt = _.rootElement;
return (new js.JsObject.fromBrowserObject(elt))[prop];
}

/**
* Sets the property [prop] to [value] through the JS interface.
* [elt] is optional and defaults to the [TestBed]'s rootElement.
*/
void setCustomProp(String prop, value, [Element elt]) {
if (elt == null) elt = _.rootElement;
(new js.JsObject.fromBrowserObject(_.rootElement))[prop] = value;
}

beforeEach((TestBed tb) {
_ = tb;
});
Expand Down Expand Up @@ -58,5 +71,15 @@ main() {
expect(customProp('ng-bind')).toEqual("hello");
expect(_.rootElement).toHaveText('hello');
});

it('should support two-way bindings for components that trigger a change event', () {
registerElement('tests-twoway', {});
_.compile('<tests-twoway bind-prop="x"></tests-twoway>');

setCustomProp('prop', 6);
_.rootElement.dispatchEvent(new Event.eventType('CustomEvent', 'change'));

expect(_.rootScope.context['x']).toEqual(6);
});
});
}