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

Commit 59323da

Browse files
rkirovchirayuk
authored andcommitted
fix(directive-injector): Pass the correct injector into nested views
Replace DefaultDirectiveInjector with DirectiveInjector (with parent = null). Application Injector reference is passed through view creation and passed into new Directive Injector (instead of using parentInjector.appInjector, which is wrong). New public method on dependency injector - parentGet. Allowing to get through the usual chain but skipping itself (used for NgControl). Remove EventListener from View. Closes #1244
1 parent 3e44a54 commit 59323da

32 files changed

+240
-196
lines changed

lib/application.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ abstract class Application {
180180
DirectiveMap directiveMap = injector.getByKey(DIRECTIVE_MAP_KEY);
181181
RootScope rootScope = injector.getByKey(ROOT_SCOPE_KEY);
182182
ViewFactory viewFactory = compiler(rootElements, directiveMap);
183-
viewFactory(rootScope, injector.get(DirectiveInjector), rootElements);
183+
viewFactory(rootScope, null, rootElements);
184184
} catch (e, s) {
185185
exceptionHandler(e, s);
186186
}

lib/core_dom/common.dart

-18
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,3 @@ class DirectiveRef {
4343
}
4444
}
4545

46-
/**
47-
* Creates a child injector that allows loading new directives, formatters and
48-
* services from the provided modules.
49-
*/
50-
Injector forceNewDirectivesAndFormatters(Injector injector, DirectiveInjector dirInjector,
51-
List<Module> modules) {
52-
modules.add(new Module()
53-
..bind(Scope, toFactory: (Injector injector) {
54-
var scope = injector.parent.getByKey(SCOPE_KEY);
55-
return scope.createChild(new PrototypeMap(scope.context));
56-
}, inject: [INJECTOR_KEY])
57-
..bind(DirectiveMap)
58-
..bind(FormatterMap)
59-
..bind(DirectiveInjector,
60-
toFactory: () => new DefaultDirectiveInjector.newAppInjector(dirInjector, injector)));
61-
62-
return new ModuleInjector(modules, injector);
63-
}

lib/core_dom/directive_injector.dart

+48-55
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ const int CONTENT_PORT_KEY_ID = 16;
5252
const int EVENT_HANDLER_KEY_ID = 17;
5353
const int KEEP_ME_LAST = 18;
5454

55+
EventHandler eventHandler(DirectiveInjector di) => di._eventHandler;
56+
5557
class DirectiveInjector implements DirectiveBinder {
5658
static bool _isInit = false;
5759
static initUID() {
@@ -100,8 +102,8 @@ class DirectiveInjector implements DirectiveBinder {
100102
, KEEP_ME_LAST
101103
];
102104

103-
final DirectiveInjector parent;
104-
final Injector appInjector;
105+
final DirectiveInjector _parent;
106+
final Injector _appInjector;
105107
final Node _node;
106108
final NodeAttrs _nodeAttrs;
107109
final Animate _animate;
@@ -140,17 +142,8 @@ class DirectiveInjector implements DirectiveBinder {
140142

141143
static Binding _temp_binding = new Binding();
142144

143-
DirectiveInjector(parent, appInjector, this._node, this._nodeAttrs, this._eventHandler,
144-
this.scope, this._animate)
145-
: appInjector = appInjector,
146-
parent = parent == null ? new DefaultDirectiveInjector(appInjector) : parent;
147-
148-
DirectiveInjector._default(this.parent, this.appInjector)
149-
: _node = null,
150-
_nodeAttrs = null,
151-
_eventHandler = null,
152-
scope = null,
153-
_animate = null;
145+
DirectiveInjector(this._parent, this._appInjector, this._node, this._nodeAttrs, this._eventHandler,
146+
this.scope, this._animate);
154147

155148
bind(key, {dynamic toValue: DEFAULT_VALUE,
156149
Function toFactory: DEFAULT_VALUE,
@@ -190,12 +183,17 @@ class DirectiveInjector implements DirectiveBinder {
190183
else { throw 'Maximum number of directives per element reached.'; }
191184
}
192185

186+
// Get a key from the directive injector chain. When it is exhausted, get from
187+
// the current application injector chain.
193188
Object get(Type type) => getByKey(new Key(type));
194189

190+
// Same behavior as get but skips the current injector.
191+
Object parentGet(Type type) => parentGetByKey(new Key(type));
192+
195193
Object getByKey(Key key) {
196194
var oldTag = _TAG_GET.makeCurrent();
197195
try {
198-
return _getByKey(key);
196+
return _getByKey(key, _appInjector);
199197
} on ResolvingError catch (e, s) {
200198
e.appendKey(key);
201199
rethrow;
@@ -204,7 +202,15 @@ class DirectiveInjector implements DirectiveBinder {
204202
}
205203
}
206204

207-
Object _getByKey(Key key) {
205+
Object parentGetByKey(Key key) {
206+
if (_parent == null) {
207+
return _appInjector.getByKey(key);
208+
} else {
209+
return _parent._getByKey(key, _appInjector);
210+
}
211+
}
212+
213+
Object _getByKey(Key key, Injector appInjector) {
208214
int uid = key.uid;
209215
if (uid == null || uid == UNDEFINED_ID) return appInjector.getByKey(key);
210216
bool isDirective = uid < 0;
@@ -224,8 +230,10 @@ class DirectiveInjector implements DirectiveBinder {
224230
if (_key8 == null) break; if (identical(_key8, k)) return _obj8 == null ? _obj8 = _new(_pKeys8, _factory8) : _obj8;
225231
if (_key9 == null) break; if (identical(_key9, k)) return _obj9 == null ? _obj9 = _new(_pKeys9, _factory9) : _obj9;
226232
} while (false);
233+
var parent = this._parent;
234+
if (parent == null) return i.getByKey(k);
227235
switch (visType) {
228-
case VISIBILITY_LOCAL: return appInjector.getByKey(k);
236+
case VISIBILITY_LOCAL: return i.getByKey(k);
229237
case VISIBILITY_DIRECT_CHILD: return parent._getDirectiveByKey(k, VISIBILITY_LOCAL, i);
230238
case VISIBILITY_CHILDREN: return parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
231239
// SHADOW
@@ -234,6 +242,7 @@ class DirectiveInjector implements DirectiveBinder {
234242
case VISIBILITY_COMPONENT_CHILDREN: return parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
235243
default: throw null;
236244
}
245+
237246
}
238247

239248
List get directives {
@@ -253,7 +262,7 @@ class DirectiveInjector implements DirectiveBinder {
253262

254263
Object _getById(int keyId) {
255264
switch(keyId) {
256-
case INJECTOR_KEY_ID: return appInjector;
265+
case INJECTOR_KEY_ID: return _appInjector;
257266
case DIRECTIVE_INJECTOR_KEY_ID: return this;
258267
case NODE_KEY_ID: return _node;
259268
case ELEMENT_KEY_ID: return _node;
@@ -263,7 +272,8 @@ class DirectiveInjector implements DirectiveBinder {
263272
case ELEMENT_PROBE_KEY_ID: return elementProbe;
264273
case NG_ELEMENT_KEY_ID: return ngElement;
265274
case EVENT_HANDLER_KEY_ID: return _eventHandler;
266-
case CONTENT_PORT_KEY_ID: return parent._getById(keyId);
275+
case CONTENT_PORT_KEY_ID:
276+
return _parent == null ? null : _parent._getById(keyId);
267277
default: new NoProviderError(_KEYS[keyId]);
268278
}
269279
}
@@ -272,29 +282,30 @@ class DirectiveInjector implements DirectiveBinder {
272282
var oldTag = _TAG_GET.makeCurrent();
273283
int size = paramKeys.length;
274284
var obj;
285+
var appInjector = this._appInjector;
275286
if (size > 15) {
276287
var params = new List(paramKeys.length);
277288
for(var i = 0; i < paramKeys.length; i++) {
278-
params[i] = _getByKey(paramKeys[i]);
289+
params[i] = _getByKey(paramKeys[i], appInjector);
279290
}
280291
_TAG_INSTANTIATE.makeCurrent();
281292
obj = Function.apply(fn, params);
282293
} else {
283-
var a01 = size >= 01 ? _getByKey(paramKeys[00]) : null;
284-
var a02 = size >= 02 ? _getByKey(paramKeys[01]) : null;
285-
var a03 = size >= 03 ? _getByKey(paramKeys[02]) : null;
286-
var a04 = size >= 04 ? _getByKey(paramKeys[03]) : null;
287-
var a05 = size >= 05 ? _getByKey(paramKeys[04]) : null;
288-
var a06 = size >= 06 ? _getByKey(paramKeys[05]) : null;
289-
var a07 = size >= 07 ? _getByKey(paramKeys[06]) : null;
290-
var a08 = size >= 08 ? _getByKey(paramKeys[07]) : null;
291-
var a09 = size >= 09 ? _getByKey(paramKeys[08]) : null;
292-
var a10 = size >= 10 ? _getByKey(paramKeys[09]) : null;
293-
var a11 = size >= 11 ? _getByKey(paramKeys[10]) : null;
294-
var a12 = size >= 12 ? _getByKey(paramKeys[11]) : null;
295-
var a13 = size >= 13 ? _getByKey(paramKeys[12]) : null;
296-
var a14 = size >= 14 ? _getByKey(paramKeys[13]) : null;
297-
var a15 = size >= 15 ? _getByKey(paramKeys[14]) : null;
294+
var a01 = size >= 01 ? _getByKey(paramKeys[00], appInjector) : null;
295+
var a02 = size >= 02 ? _getByKey(paramKeys[01], appInjector) : null;
296+
var a03 = size >= 03 ? _getByKey(paramKeys[02], appInjector) : null;
297+
var a04 = size >= 04 ? _getByKey(paramKeys[03], appInjector) : null;
298+
var a05 = size >= 05 ? _getByKey(paramKeys[04], appInjector) : null;
299+
var a06 = size >= 06 ? _getByKey(paramKeys[05], appInjector) : null;
300+
var a07 = size >= 07 ? _getByKey(paramKeys[06], appInjector) : null;
301+
var a08 = size >= 08 ? _getByKey(paramKeys[07], appInjector) : null;
302+
var a09 = size >= 09 ? _getByKey(paramKeys[08], appInjector) : null;
303+
var a10 = size >= 10 ? _getByKey(paramKeys[09], appInjector) : null;
304+
var a11 = size >= 11 ? _getByKey(paramKeys[10], appInjector) : null;
305+
var a12 = size >= 12 ? _getByKey(paramKeys[11], appInjector) : null;
306+
var a13 = size >= 13 ? _getByKey(paramKeys[12], appInjector) : null;
307+
var a14 = size >= 14 ? _getByKey(paramKeys[13], appInjector) : null;
308+
var a15 = size >= 15 ? _getByKey(paramKeys[14], appInjector) : null;
298309
_TAG_INSTANTIATE.makeCurrent();
299310
switch(size) {
300311
case 00: obj = fn(); break;
@@ -322,7 +333,7 @@ class DirectiveInjector implements DirectiveBinder {
322333

323334
ElementProbe get elementProbe {
324335
if (_elementProbe == null) {
325-
ElementProbe parentProbe = parent is DirectiveInjector ? parent.elementProbe : null;
336+
ElementProbe parentProbe = _parent == null ? null : _parent.elementProbe;
326337
_elementProbe = new ElementProbe(parentProbe, _node, this, scope);
327338
}
328339
return _elementProbe;
@@ -353,7 +364,7 @@ class TemplateDirectiveInjector extends DirectiveInjector {
353364
case VIEW_PORT_KEY_ID: return ((_viewPort) == null) ?
354365
_viewPort = new ViewPort(this, scope, _node, _animate) : _viewPort;
355366
case BOUND_VIEW_FACTORY_KEY_ID: return (_boundViewFactory == null) ?
356-
_boundViewFactory = _viewFactory.bind(this.parent) : _boundViewFactory;
367+
_boundViewFactory = _viewFactory.bind(this._parent) : _boundViewFactory;
357368
default: return super._getById(keyId);
358369
}
359370
}
@@ -409,27 +420,9 @@ class ShadowDomComponentDirectiveInjector extends ComponentDirectiveInjector {
409420

410421
ElementProbe get elementProbe {
411422
if (_elementProbe == null) {
412-
ElementProbe parentProbe =
413-
parent is DirectiveInjector ? parent.elementProbe : parent.getByKey(ELEMENT_PROBE_KEY);
423+
ElementProbe parentProbe = _parent == null ? null : _parent.elementProbe;
414424
_elementProbe = new ElementProbe(parentProbe, _shadowRoot, this, scope);
415425
}
416426
return _elementProbe;
417427
}
418428
}
419-
420-
@Injectable()
421-
class DefaultDirectiveInjector extends DirectiveInjector {
422-
DefaultDirectiveInjector(Injector appInjector): super._default(null, appInjector);
423-
DefaultDirectiveInjector.newAppInjector(DirectiveInjector parent, Injector appInjector)
424-
: super._default(parent, appInjector);
425-
426-
Object getByKey(Key key) => appInjector.getByKey(key);
427-
_getDirectiveByKey(Key key, int visType, Injector i) =>
428-
parent == null ? i.getByKey(key) : parent._getDirectiveByKey(key, visType, i);
429-
_getById(int keyId) {
430-
switch (keyId) {
431-
case CONTENT_PORT_KEY_ID: return null;
432-
default: throw new NoProviderError(DirectiveInjector._KEYS[keyId]);
433-
}
434-
}
435-
}

lib/core_dom/directive_map.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ class DirectiveMap {
1313
DirectiveSelectorFactory _directiveSelectorFactory;
1414
FormatterMap _formatters;
1515
DirectiveSelector _selector;
16+
Injector _injector;
1617

17-
DirectiveMap(Injector injector,
18+
DirectiveMap(Injector this._injector,
1819
this._formatters,
1920
MetadataExtractor metadataExtractor,
2021
this._directiveSelectorFactory) {
21-
(injector as ModuleInjector).types.forEach((type) {
22+
(_injector as ModuleInjector).types.forEach((type) {
2223
metadataExtractor(type)
2324
.where((annotation) => annotation is Directive)
2425
.forEach((Directive directive) {
@@ -29,7 +30,7 @@ class DirectiveMap {
2930

3031
DirectiveSelector get selector {
3132
if (_selector != null) return _selector;
32-
return _selector = _directiveSelectorFactory.selector(this, _formatters);
33+
return _selector = _directiveSelectorFactory.selector(this, _injector, _formatters);
3334
}
3435

3536
List<DirectiveTypeTuple> operator[](String key) {

lib/core_dom/element_binder.dart

+16-11
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ class TemplateElementBinder extends ElementBinder {
1414
return _directiveCache = [template];
1515
}
1616

17-
TemplateElementBinder(perf, expando, parser, config,
17+
TemplateElementBinder(perf, expando, parser, config, appInjector,
1818
this.template, this.templateBinder,
1919
onEvents, bindAttrs, childMode)
20-
: super(perf, expando, parser, config,
20+
: super(perf, expando, parser, config, appInjector,
2121
null, null, onEvents, bindAttrs, childMode);
2222

2323
String toString() => "[TemplateElementBinder template:$template]";
@@ -47,6 +47,8 @@ class ElementBinder {
4747
final Expando _expando;
4848
final Parser _parser;
4949
final CompilerConfig _config;
50+
final Injector _appInjector;
51+
Animate _animate;
5052

5153
final Map onEvents;
5254
final Map bindAttrs;
@@ -60,8 +62,10 @@ class ElementBinder {
6062
final String childMode;
6163

6264
ElementBinder(this._perf, this._expando, this._parser, this._config,
63-
this.componentData, this.decorators,
64-
this.onEvents, this.bindAttrs, this.childMode);
65+
this._appInjector, this.componentData, this.decorators,
66+
this.onEvents, this.bindAttrs, this.childMode) {
67+
_animate = _appInjector.getByKey(ANIMATE_KEY);
68+
}
6569

6670
final bool hasTemplate = false;
6771

@@ -257,20 +261,21 @@ class ElementBinder {
257261

258262
DirectiveInjector bind(View view, Scope scope,
259263
DirectiveInjector parentInjector,
260-
dom.Node node, EventHandler eventHandler, Animate animate) {
264+
dom.Node node) {
261265
var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null;
262266

263267
var directiveRefs = _usableDirectiveRefs;
264268
if (!hasDirectivesOrEvents) return parentInjector;
265269

266270
DirectiveInjector nodeInjector;
271+
var parentEventHandler = parentInjector == null ?
272+
_appInjector.getByKey(EVENT_HANDLER_KEY) :
273+
eventHandler(parentInjector);
267274
if (this is TemplateElementBinder) {
268-
nodeInjector = new TemplateDirectiveInjector(parentInjector, parentInjector.appInjector,
269-
node, nodeAttrs, eventHandler, scope, animate,
270-
(this as TemplateElementBinder).templateViewFactory);
275+
nodeInjector = new TemplateDirectiveInjector(parentInjector, _appInjector,
276+
node, nodeAttrs, parentEventHandler, scope, _animate, (this as TemplateElementBinder).templateViewFactory);
271277
} else {
272-
nodeInjector = new DirectiveInjector(parentInjector, parentInjector.appInjector,
273-
node, nodeAttrs, eventHandler, scope, animate);
278+
nodeInjector = new DirectiveInjector(parentInjector, _appInjector, node, nodeAttrs, parentEventHandler, scope, _animate);
274279
}
275280

276281
for(var i = 0; i < directiveRefs.length; i++) {
@@ -299,7 +304,7 @@ class ElementBinder {
299304

300305
if (onEvents.isNotEmpty) {
301306
onEvents.forEach((event, value) {
302-
view.registerEvent(EventHandler.attrNameToEventName(event));
307+
parentEventHandler.register(EventHandler.attrNameToEventName(event));
303308
});
304309
}
305310
return nodeInjector;

lib/core_dom/element_binder_builder.dart

+9-7
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ class ElementBinderFactory {
1515
this.astParser, this.componentFactory, this.shadowDomComponentFactory, this.transcludingComponentFactory);
1616

1717
// TODO: Optimize this to re-use a builder.
18-
ElementBinderBuilder builder(FormatterMap formatters, DirectiveMap directives) =>
19-
new ElementBinderBuilder(this,formatters, directives);
18+
ElementBinderBuilder builder(FormatterMap formatters, DirectiveMap directives, Injector injector) =>
19+
new ElementBinderBuilder(this, formatters, directives, injector);
2020

2121
ElementBinder binder(ElementBinderBuilder b) =>
2222

23-
new ElementBinder(_perf, _expando, _parser, _config,
23+
new ElementBinder(_perf, _expando, _parser, _config, b._injector,
2424
b.componentData, b.decorators, b.onEvents, b.bindAttrs, b.childMode);
2525

26-
TemplateElementBinder templateBinder(ElementBinderBuilder b, ElementBinder transclude) =>
27-
new TemplateElementBinder(_perf, _expando, _parser, _config,
26+
TemplateElementBinder templateBinder(
27+
ElementBinderBuilder b, ElementBinder transclude) =>
28+
new TemplateElementBinder(_perf, _expando, _parser, _config, b._injector,
2829
b.template, transclude, b.onEvents, b.bindAttrs, b.childMode);
2930
}
3031

@@ -45,13 +46,14 @@ class ElementBinderBuilder {
4546
final bindAttrs = new HashMap<String, AST>();
4647

4748
final decorators = <DirectiveRef>[];
49+
final Injector _injector;
4850
DirectiveRef template;
4951
BoundComponentData componentData;
5052

5153
// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
5254
String childMode = Directive.COMPILE_CHILDREN;
5355

54-
ElementBinderBuilder(this._factory, this._formatters, this._directives);
56+
ElementBinderBuilder(this._factory, this._formatters, this._directives, this._injector);
5557

5658
/**
5759
* Adds [DirectiveRef]s to this [ElementBinderBuilder].
@@ -79,7 +81,7 @@ class ElementBinderBuilder {
7981
factory = _factory.componentFactory;
8082
}
8183

82-
componentData = new BoundComponentData(ref, () => factory.bind(ref, _directives));
84+
componentData = new BoundComponentData(ref, () => factory.bind(ref, _directives, _injector));
8385
} else {
8486
decorators.add(ref);
8587
}

0 commit comments

Comments
 (0)