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

Commit

Permalink
fix(compiler): support filters in attribute expressions
Browse files Browse the repository at this point in the history
Fixes #571
Closes #580
  • Loading branch information
pavelgj authored and mhevery committed Feb 19, 2014
1 parent cec3eda commit 8f020f9
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 10 deletions.
3 changes: 2 additions & 1 deletion lib/core_dom/block_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<Type, _ComponentFactory> fctrs;
var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null;
ElementProbe probe;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/core_dom/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ List<dom.Node> 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;
Expand Down
16 changes: 8 additions & 8 deletions lib/core_dom/compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();
Expand All @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions test/core_dom/compiler_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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'''<expr-attr-component expr="'Misko' | hello" one-way="'James' | hello" once="'Chirayu' | hello"></expr-attr-component>''');
$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'<div><non-assignable-mapping></non-assignable-mapping</div>');
Expand Down Expand Up @@ -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'<content></content>',
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;
}
}

0 comments on commit 8f020f9

Please sign in to comment.