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

fix(compiler): support filters in attribute expressions #580

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
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;
}
}