From c53dc779862c8a36fdb01a8032b99a03165a3ec9 Mon Sep 17 00:00:00 2001 From: James deBoer Date: Fri, 25 Jul 2014 06:27:37 -0700 Subject: [PATCH] feat(element binder): Bind to Web Component properties Closes #1277 --- example/web/paper_progress.html | 7 ++- lib/core_dom/element_binder.dart | 10 ++++- test/core_dom/web_components_spec.dart | 62 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 test/core_dom/web_components_spec.dart diff --git a/example/web/paper_progress.html b/example/web/paper_progress.html index 55cb967d3..422f6f78a 100644 --- a/example/web/paper_progress.html +++ b/example/web/paper_progress.html @@ -12,15 +12,18 @@ href="bower_components/paper-progress/paper-progress.html"> +

A quick demo of the Polymer paper-progress widget in an AngularDart app.

-

The max ({{max}}) and value ({{curValue}}) properties are bound through attribute intropolation

+

The max ({{max}}) and value ({{curValue}}) properties are bound through bind-* semantics

Text from Angular: {{text}}

- +

diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 79f4e919d..0a8fac939 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -62,7 +62,7 @@ class ElementBinder { } bool get hasDirectivesOrEvents => - _usableDirectiveRefs.isNotEmpty || onEvents.isNotEmpty; + _usableDirectiveRefs.isNotEmpty || onEvents.isNotEmpty || bindAttrs.isNotEmpty; void _bindTwoWay(tasks, AST ast, scope, directiveScope, controller, AST dstAST) { @@ -283,6 +283,14 @@ class ElementBinder { _link(nodeInjector, scope, nodeAttrs); + var jsNode; + bindAttrs.forEach((String prop, ast) { + if (jsNode == null) jsNode = new js.JsObject.fromBrowserObject(node); + scope.watchAST(ast, (v, _) { + jsNode[prop] = v; + }); + }); + if (onEvents.isNotEmpty) { onEvents.forEach((event, value) { view.registerEvent(EventHandler.attrNameToEventName(event)); diff --git a/test/core_dom/web_components_spec.dart b/test/core_dom/web_components_spec.dart new file mode 100644 index 000000000..e20fbaa46 --- /dev/null +++ b/test/core_dom/web_components_spec.dart @@ -0,0 +1,62 @@ +library angular.dom.web_components_spec; + +import '../_specs.dart'; +import 'dart:js' as js; + +registerElement(String name, prototype) { + return (new js.JsObject.fromBrowserObject(document)).callMethod('registerElement', + [name, new js.JsObject.jsify({"prototype": prototype })]); +} + + + +main() { + describe('WebComponent support', () { + TestBed _; + + customProp(String prop, [elt]) { + if (elt == null) elt = _.rootElement; + return (new js.JsObject.fromBrowserObject(elt))[prop]; + } + + beforeEach((TestBed tb) { + _ = tb; + }); + + it('should create custom elements', () { + registerElement('tests-basic', {'prop-x': 6}); + + // Create a web component + _.compile(''); + expect(customProp('prop-x')).toEqual(6); + }); + + + it('should bind to Custom Element properties', () { + registerElement('tests-bound', {'prop-y': 10}); + _.compile(''); + + // Scope has not been digested yet + expect(customProp('prop-y')).toEqual(10); + + _.rootScope.apply(); + expect(customProp('prop-y')).toEqual(27); + }); + + + it('should bind to a non-existent property', () { + registerElement('tests-empty', {}); + _.compile(''); + _.rootScope.apply(); + expect(customProp('new-prop')).toEqual(27); + }); + + it('should bind to both directives and properties', () { + registerElement('tests-double', {}); + _.compile(''); + _.rootScope.apply(); + expect(customProp('ng-bind')).toEqual("hello"); + expect(_.rootElement).toHaveText('hello'); + }); + }); +}