From 7921aefe7e4e5ac745ca3e70c29dc96d3996d6c7 Mon Sep 17 00:00:00 2001 From: Pavel Jbanov Date: Tue, 18 Feb 2014 14:17:14 -0500 Subject: [PATCH] fix(compiler): support filters in attribute expressions Fixes #571 --- lib/core_dom/block_factory.dart | 3 ++- lib/core_dom/common.dart | 2 +- lib/core_dom/compiler.dart | 16 ++++++------- test/core_dom/compiler_spec.dart | 39 ++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/lib/core_dom/block_factory.dart b/lib/core_dom/block_factory.dart index 8856e37ca..957bd880f 100644 --- a/lib/core_dom/block_factory.dart +++ b/lib/core_dom/block_factory.dart @@ -99,6 +99,7 @@ class BlockFactory { assert((timerId = _perf.startTimer('ng.block.link.setUp', _html(node))) != false); Injector nodeInjector; Scope scope = parentInjector.get(Scope); + FilterMap filters = parentInjector.get(FilterMap); Map fctrs; var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null; ElementProbe probe; @@ -199,7 +200,7 @@ class BlockFactory { } if (nodeAttrs == null) nodeAttrs = new _AnchorAttrs(ref); for(var map in ref.mappings) { - map(nodeAttrs, scope, controller); + map(nodeAttrs, scope, controller, filters); } if (controller is NgAttachAware) { var removeWatcher; diff --git a/lib/core_dom/common.dart b/lib/core_dom/common.dart index 012023c00..013a6ddd1 100644 --- a/lib/core_dom/common.dart +++ b/lib/core_dom/common.dart @@ -4,7 +4,7 @@ List cloneElements(elements) { return elements.map((el) => el.clone(true)).toList(); } -typedef ApplyMapping(NodeAttrs attrs, Scope scope, Object dst); +typedef ApplyMapping(NodeAttrs attrs, Scope scope, Object dst, FilterMap filters); class DirectiveRef { final dom.Node element; diff --git a/lib/core_dom/compiler.dart b/lib/core_dom/compiler.dart index 45add788e..7e597ce4e 100644 --- a/lib/core_dom/compiler.dart +++ b/lib/core_dom/compiler.dart @@ -146,17 +146,17 @@ class Compiler { ApplyMapping mappingFn; switch (mode) { case '@': - mappingFn = (NodeAttrs attrs, Scope scope, Object dst) { + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters) { attrs.observe(attrName, (value) => dstPathFn.assign(dst, value)); }; break; case '<=>': - mappingFn = (NodeAttrs attrs, Scope scope, Object dst) { + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters) { if (attrs[attrName] == null) return; Expression attrExprFn = _parser(attrs[attrName]); var shadowValue = null; scope.$watch( - () => attrExprFn.eval(scope), + () => attrExprFn.eval(scope, filters), (v) => dstPathFn.assign(dst, shadowValue = v), attrs[attrName]); if (attrExprFn.isAssignable) { @@ -173,22 +173,22 @@ class Compiler { }; break; case '=>': - mappingFn = (NodeAttrs attrs, Scope scope, Object dst) { + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters) { if (attrs[attrName] == null) return; Expression attrExprFn = _parser(attrs[attrName]); scope.$watch( - () => attrExprFn.eval(scope), + () => attrExprFn.eval(scope, filters), (v) => dstPathFn.assign(dst, v), attrs[attrName]); }; break; case '=>!': - mappingFn = (NodeAttrs attrs, Scope scope, Object dst) { + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters) { if (attrs[attrName] == null) return; Expression attrExprFn = _parser(attrs[attrName]); var stopWatching; stopWatching = scope.$watch( - () => attrExprFn.eval(scope), + () => attrExprFn.eval(scope, filters), (value) { if (dstPathFn.assign(dst, value) != null) { stopWatching(); @@ -198,7 +198,7 @@ class Compiler { }; break; case '&': - mappingFn = (NodeAttrs attrs, Scope scope, Object dst) { + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters) { dstPathFn.assign(dst, _parser(attrs[attrName]).bind(scope, ScopeLocals.wrapper)); }; break; diff --git a/test/core_dom/compiler_spec.dart b/test/core_dom/compiler_spec.dart index 6cc6b60bf..fa8c8bcd3 100644 --- a/test/core_dom/compiler_spec.dart +++ b/test/core_dom/compiler_spec.dart @@ -180,6 +180,8 @@ main() => describe('dte.compiler', () { module.type(LogComponent); module.type(AttachDetachComponent); module.type(SimpleComponent); + module.type(ExprAttrComponent); + module.type(SayHelloFilter); })); it('should select on element', async(inject((NgZone zone) { @@ -364,6 +366,16 @@ main() => describe('dte.compiler', () { }).toThrow("Unknown mapping 'foo\' for attribute 'attr'."); }))); + it('should support filters in attribute expressions', async(inject(() { + var element = $(r''''''); + $compile(element, directives)(injector, element); + ExprAttrComponent component = $rootScope['exprAttrComponent']; + $rootScope.$digest(); + expect(component.expr).toEqual('Hello, Misko!'); + expect(component.oneWay).toEqual('Hello, James!'); + expect(component.exprOnce).toEqual('Hello, Chirayu!'); + }))); + it('should error on non-asignable-mapping', async(inject(() { expect(() { var element = $(r'
'); @@ -787,3 +799,30 @@ class MissingSelector {} @NgComponent(selector: 'buttonbar button') class InvalidSelector {} +@NgFilter(name:'hello') +class SayHelloFilter { + call(String str) { + return 'Hello, $str!'; + } +} + +@NgComponent( + selector: 'expr-attr-component', + template: r'', + publishAs: 'ctrl', + map: const { + 'expr': '<=>expr', + 'one-way': '=>oneWay', + 'once': '=>!exprOnce' + } +) +class ExprAttrComponent { + var expr; + var oneWay; + var exprOnce; + + ExprAttrComponent(Scope scope) { + scope.$root.exprAttrComponent = this; + } +} +