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

Commit ebf576b

Browse files
committed
fix(directive-injector): Fixes for Direcive Injector.
Breaking change: Regular (application) injectors cannot construct DirectiveInjectors (DI). Only compilers create DI as part of view creation process. Deprecation: directive injector parent is now private. New public method on dependency injector - parentGet, which allows to get through the usual chain but skipping itself. Component Injectors now break the resolution chain (except when called directly.) TestBed does not need DI in its constructor. Internal changes: - Application Injector reference is passed through view creation and passed into new Directive Injector (instead of using parentInjector.appInjector, which is wrong when used with ng-view). - Unwind recursion from the directive injector. - Remove EventListener from View. - Replace DefaultDirectiveInjector with DirectiveInjector (with parent = null). - Component visibility handled outside the visibility enum. - Removed Shadowless and ShadowDirectiveInjector subclasses. Closes #1111
1 parent 75d4064 commit ebf576b

30 files changed

+343
-237
lines changed

lib/application.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ abstract class Application {
190190
DirectiveMap directiveMap = injector.getByKey(DIRECTIVE_MAP_KEY);
191191
RootScope rootScope = injector.getByKey(ROOT_SCOPE_KEY);
192192
ViewFactory viewFactory = compiler(rootElements, directiveMap);
193-
viewFactory(rootScope, injector.get(DirectiveInjector), rootElements);
193+
viewFactory(rootScope, null, rootElements);
194194
} catch (e, s) {
195195
exceptionHandler(e, s);
196196
}

lib/core_dom/common.dart

-18
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,3 @@ class DirectiveRef {
4545
}
4646
}
4747

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

lib/core_dom/directive_injector.dart

+83-101
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@ final CONTENT_PORT_KEY = new Key(ContentPort);
2424
final TEMPLATE_LOADER_KEY = new Key(TemplateLoader);
2525
final SHADOW_ROOT_KEY = new Key(ShadowRoot);
2626

27+
final num MAX_DEPTH = 1 << 30;
28+
2729
const int VISIBILITY_LOCAL = -1;
2830
const int VISIBILITY_DIRECT_CHILD = -2;
2931
const int VISIBILITY_CHILDREN = -3;
30-
const int VISIBILITY_COMPONENT_OFFSET = VISIBILITY_CHILDREN;
31-
const int VISIBILITY_COMPONENT_LOCAL = VISIBILITY_LOCAL + VISIBILITY_COMPONENT_OFFSET;
32-
const int VISIBILITY_COMPONENT_DIRECT_CHILD = VISIBILITY_DIRECT_CHILD + VISIBILITY_COMPONENT_OFFSET;
33-
const int VISIBILITY_COMPONENT_CHILDREN = VISIBILITY_CHILDREN + VISIBILITY_COMPONENT_OFFSET;
3432

3533
const int UNDEFINED_ID = 0;
3634
const int INJECTOR_KEY_ID = 1;
@@ -52,6 +50,8 @@ const int CONTENT_PORT_KEY_ID = 16;
5250
const int EVENT_HANDLER_KEY_ID = 17;
5351
const int KEEP_ME_LAST = 18;
5452

53+
EventHandler eventHandler(DirectiveInjector di) => di._eventHandler;
54+
5555
class DirectiveInjector implements DirectiveBinder {
5656
static bool _isInit = false;
5757
static initUID() {
@@ -99,9 +99,9 @@ class DirectiveInjector implements DirectiveBinder {
9999
, EVENT_HANDLER_KEY
100100
, KEEP_ME_LAST
101101
];
102-
102+
103103
final DirectiveInjector _parent;
104-
final Injector appInjector;
104+
final Injector _appInjector;
105105
final Node _node;
106106
final NodeAttrs _nodeAttrs;
107107
final Animate _animate;
@@ -134,21 +134,17 @@ class DirectiveInjector implements DirectiveBinder {
134134
case VISIBILITY_LOCAL: return Visibility.LOCAL;
135135
case VISIBILITY_DIRECT_CHILD: return Visibility.DIRECT_CHILD;
136136
case VISIBILITY_CHILDREN: return Visibility.CHILDREN;
137-
case VISIBILITY_COMPONENT_LOCAL: return Visibility.LOCAL;
138-
case VISIBILITY_COMPONENT_DIRECT_CHILD: return Visibility.DIRECT_CHILD;
139-
case VISIBILITY_COMPONENT_CHILDREN: return Visibility.CHILDREN;
140137
default: return null;
141138
}
142139
}
143140

144141
static Binding _tempBinding = new Binding();
145142

146-
DirectiveInjector(DirectiveInjector parent, Injector appInjector, this._node, this._nodeAttrs,
143+
DirectiveInjector(this._parent, appInjector, this._node, this._nodeAttrs,
147144
this._eventHandler, this.scope, this._animate)
148-
: appInjector = appInjector,
149-
_parent = parent == null ? new DefaultDirectiveInjector(appInjector) : parent;
145+
: _appInjector = appInjector;
150146

151-
DirectiveInjector._default(this._parent, this.appInjector)
147+
DirectiveInjector._default(this._parent, this._appInjector)
152148
: _node = null,
153149
_nodeAttrs = null,
154150
_eventHandler = null,
@@ -195,54 +191,72 @@ class DirectiveInjector implements DirectiveBinder {
195191
else { throw 'Maximum number of directives per element reached.'; }
196192
}
197193

194+
// Get a key from the directive injector chain. When it is exhausted, get from
195+
// the current application injector chain.
198196
Object get(Type type) => getByKey(new Key(type));
199197
Object getFromParent(Type type) => _parent.get(type);
200198

201199
Object getByKey(Key key) {
202200
var oldTag = _TAG_GET.makeCurrent();
203201
try {
204-
return _getByKey(key);
202+
return _getByKey(key, _appInjector);
205203
} on ResolvingError catch (e, s) {
206204
e.appendKey(key);
207205
rethrow;
208206
} finally {
209207
oldTag.makeCurrent();
210208
}
211209
}
212-
Object getFromParentByKey(Key key) => _parent.getByKey(key);
213210

214-
Object _getByKey(Key key) {
211+
Object getFromParentByKey(Key key) {
212+
if (_parent == null) {
213+
return _appInjector.getByKey(key);
214+
} else {
215+
return _parent._getByKey(key, _appInjector);
216+
}
217+
}
218+
219+
Object _getByKey(Key key, Injector appInjector) {
215220
int uid = key.uid;
216221
if (uid == null || uid == UNDEFINED_ID) return appInjector.getByKey(key);
217222
bool isDirective = uid < 0;
218223
return isDirective ? _getDirectiveByKey(key, uid, appInjector) : _getById(uid);
219224
}
220225

221-
Object _getDirectiveByKey(Key k, int visType, Injector i) {
222-
do {
223-
if (_key0 == null) break; if (identical(_key0, k)) return _obj0 == null ? _obj0 = _new(_pKeys0, _factory0) : _obj0;
224-
if (_key1 == null) break; if (identical(_key1, k)) return _obj1 == null ? _obj1 = _new(_pKeys1, _factory1) : _obj1;
225-
if (_key2 == null) break; if (identical(_key2, k)) return _obj2 == null ? _obj2 = _new(_pKeys2, _factory2) : _obj2;
226-
if (_key3 == null) break; if (identical(_key3, k)) return _obj3 == null ? _obj3 = _new(_pKeys3, _factory3) : _obj3;
227-
if (_key4 == null) break; if (identical(_key4, k)) return _obj4 == null ? _obj4 = _new(_pKeys4, _factory4) : _obj4;
228-
if (_key5 == null) break; if (identical(_key5, k)) return _obj5 == null ? _obj5 = _new(_pKeys5, _factory5) : _obj5;
229-
if (_key6 == null) break; if (identical(_key6, k)) return _obj6 == null ? _obj6 = _new(_pKeys6, _factory6) : _obj6;
230-
if (_key7 == null) break; if (identical(_key7, k)) return _obj7 == null ? _obj7 = _new(_pKeys7, _factory7) : _obj7;
231-
if (_key8 == null) break; if (identical(_key8, k)) return _obj8 == null ? _obj8 = _new(_pKeys8, _factory8) : _obj8;
232-
if (_key9 == null) break; if (identical(_key9, k)) return _obj9 == null ? _obj9 = _new(_pKeys9, _factory9) : _obj9;
233-
} while (false);
234-
switch (visType) {
235-
case VISIBILITY_LOCAL: return appInjector.getByKey(k);
236-
case VISIBILITY_DIRECT_CHILD: return _parent._getDirectiveByKey(k, VISIBILITY_LOCAL, i);
237-
case VISIBILITY_CHILDREN: return _parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
238-
// SHADOW
239-
case VISIBILITY_COMPONENT_LOCAL: return _parent._getDirectiveByKey(k, VISIBILITY_LOCAL, i);
240-
case VISIBILITY_COMPONENT_DIRECT_CHILD: return _parent._getDirectiveByKey(k, VISIBILITY_DIRECT_CHILD, i);
241-
case VISIBILITY_COMPONENT_CHILDREN: return _parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
226+
num _getDepth(int visType) {
227+
switch(visType) {
228+
case VISIBILITY_LOCAL: return 0;
229+
case VISIBILITY_DIRECT_CHILD: return 1;
230+
case VISIBILITY_CHILDREN: return MAX_DEPTH;
242231
default: throw null;
243232
}
244233
}
245234

235+
_getDirectiveByKey(Key k, int visType, Injector appInjector) {
236+
num depth = _getDepth(visType);
237+
// ci stands for currentInjector, abbreviated for readability.
238+
var ci = this;
239+
while (ci != null && depth >= 0) {
240+
do {
241+
if (ci._key0 == null) break; if (identical(ci._key0, k)) return ci._obj0 == null ? ci._obj0 = ci._new(ci._pKeys0, ci._factory0) : ci._obj0;
242+
if (ci._key1 == null) break; if (identical(ci._key1, k)) return ci._obj1 == null ? ci._obj1 = ci._new(ci._pKeys1, ci._factory1) : ci._obj1;
243+
if (ci._key2 == null) break; if (identical(ci._key2, k)) return ci._obj2 == null ? ci._obj2 = ci._new(ci._pKeys2, ci._factory2) : ci._obj2;
244+
if (ci._key3 == null) break; if (identical(ci._key3, k)) return ci._obj3 == null ? ci._obj3 = ci._new(ci._pKeys3, ci._factory3) : ci._obj3;
245+
if (ci._key4 == null) break; if (identical(ci._key4, k)) return ci._obj4 == null ? ci._obj4 = ci._new(ci._pKeys4, ci._factory4) : ci._obj4;
246+
if (ci._key5 == null) break; if (identical(ci._key5, k)) return ci._obj5 == null ? ci._obj5 = ci._new(ci._pKeys5, ci._factory5) : ci._obj5;
247+
if (ci._key6 == null) break; if (identical(ci._key6, k)) return ci._obj6 == null ? ci._obj6 = ci._new(ci._pKeys6, ci._factory6) : ci._obj6;
248+
if (ci._key7 == null) break; if (identical(ci._key7, k)) return ci._obj7 == null ? ci._obj7 = ci._new(ci._pKeys7, ci._factory7) : ci._obj7;
249+
if (ci._key8 == null) break; if (identical(ci._key8, k)) return ci._obj8 == null ? ci._obj8 = ci._new(ci._pKeys8, ci._factory8) : ci._obj8;
250+
if (ci._key9 == null) break; if (identical(ci._key9, k)) return ci._obj9 == null ? ci._obj9 = ci._new(ci._pKeys9, ci._factory9) : ci._obj9;
251+
} while (false);
252+
// Component Injectors fall-through only if directly called.
253+
if ((ci is ComponentDirectiveInjector) && !identical(ci, this)) break;
254+
ci = ci._parent;
255+
depth--;
256+
}
257+
return appInjector.getByKey(k);
258+
}
259+
246260
List get directives {
247261
var directives = [];
248262
if (_obj0 != null) directives.add(_obj0);
@@ -260,7 +274,7 @@ class DirectiveInjector implements DirectiveBinder {
260274

261275
Object _getById(int keyId) {
262276
switch(keyId) {
263-
case INJECTOR_KEY_ID: return appInjector;
277+
case INJECTOR_KEY_ID: return _appInjector;
264278
case DIRECTIVE_INJECTOR_KEY_ID: return this;
265279
case NODE_KEY_ID: return _node;
266280
case ELEMENT_KEY_ID: return _node;
@@ -270,7 +284,13 @@ class DirectiveInjector implements DirectiveBinder {
270284
case ELEMENT_PROBE_KEY_ID: return elementProbe;
271285
case NG_ELEMENT_KEY_ID: return ngElement;
272286
case EVENT_HANDLER_KEY_ID: return _eventHandler;
273-
case CONTENT_PORT_KEY_ID: return _parent._getById(keyId);
287+
case CONTENT_PORT_KEY_ID:
288+
var currentInjector = _parent;
289+
while (currentInjector != null) {
290+
if (currentInjector is ComponentDirectiveInjector) return currentInjector._contentPort;
291+
currentInjector = currentInjector._parent;
292+
}
293+
return null;
274294
default: new NoProviderError(_KEYS[keyId]);
275295
}
276296
}
@@ -279,29 +299,30 @@ class DirectiveInjector implements DirectiveBinder {
279299
var oldTag = _TAG_GET.makeCurrent();
280300
int size = paramKeys.length;
281301
var obj;
302+
var appInjector = this._appInjector;
282303
if (size > 15) {
283304
var params = new List(paramKeys.length);
284305
for(var i = 0; i < paramKeys.length; i++) {
285-
params[i] = _getByKey(paramKeys[i]);
306+
params[i] = _getByKey(paramKeys[i], appInjector);
286307
}
287308
_TAG_INSTANTIATE.makeCurrent();
288309
obj = Function.apply(fn, params);
289310
} else {
290-
var a01 = size >= 01 ? _getByKey(paramKeys[00]) : null;
291-
var a02 = size >= 02 ? _getByKey(paramKeys[01]) : null;
292-
var a03 = size >= 03 ? _getByKey(paramKeys[02]) : null;
293-
var a04 = size >= 04 ? _getByKey(paramKeys[03]) : null;
294-
var a05 = size >= 05 ? _getByKey(paramKeys[04]) : null;
295-
var a06 = size >= 06 ? _getByKey(paramKeys[05]) : null;
296-
var a07 = size >= 07 ? _getByKey(paramKeys[06]) : null;
297-
var a08 = size >= 08 ? _getByKey(paramKeys[07]) : null;
298-
var a09 = size >= 09 ? _getByKey(paramKeys[08]) : null;
299-
var a10 = size >= 10 ? _getByKey(paramKeys[09]) : null;
300-
var a11 = size >= 11 ? _getByKey(paramKeys[10]) : null;
301-
var a12 = size >= 12 ? _getByKey(paramKeys[11]) : null;
302-
var a13 = size >= 13 ? _getByKey(paramKeys[12]) : null;
303-
var a14 = size >= 14 ? _getByKey(paramKeys[13]) : null;
304-
var a15 = size >= 15 ? _getByKey(paramKeys[14]) : null;
311+
var a01 = size >= 01 ? _getByKey(paramKeys[00], appInjector) : null;
312+
var a02 = size >= 02 ? _getByKey(paramKeys[01], appInjector) : null;
313+
var a03 = size >= 03 ? _getByKey(paramKeys[02], appInjector) : null;
314+
var a04 = size >= 04 ? _getByKey(paramKeys[03], appInjector) : null;
315+
var a05 = size >= 05 ? _getByKey(paramKeys[04], appInjector) : null;
316+
var a06 = size >= 06 ? _getByKey(paramKeys[05], appInjector) : null;
317+
var a07 = size >= 07 ? _getByKey(paramKeys[06], appInjector) : null;
318+
var a08 = size >= 08 ? _getByKey(paramKeys[07], appInjector) : null;
319+
var a09 = size >= 09 ? _getByKey(paramKeys[08], appInjector) : null;
320+
var a10 = size >= 10 ? _getByKey(paramKeys[09], appInjector) : null;
321+
var a11 = size >= 11 ? _getByKey(paramKeys[10], appInjector) : null;
322+
var a12 = size >= 12 ? _getByKey(paramKeys[11], appInjector) : null;
323+
var a13 = size >= 13 ? _getByKey(paramKeys[12], appInjector) : null;
324+
var a14 = size >= 14 ? _getByKey(paramKeys[13], appInjector) : null;
325+
var a15 = size >= 15 ? _getByKey(paramKeys[14], appInjector) : null;
305326
_TAG_INSTANTIATE.makeCurrent();
306327
switch(size) {
307328
case 00: obj = fn(); break;
@@ -367,14 +388,15 @@ class TemplateDirectiveInjector extends DirectiveInjector {
367388

368389
}
369390

370-
abstract class ComponentDirectiveInjector extends DirectiveInjector {
391+
class ComponentDirectiveInjector extends DirectiveInjector {
371392

372393
final TemplateLoader _templateLoader;
373394
final ShadowRoot _shadowRoot;
395+
final ContentPort _contentPort;
374396

375397
ComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
376398
EventHandler eventHandler, Scope scope,
377-
this._templateLoader, this._shadowRoot)
399+
this._templateLoader, this._shadowRoot, this._contentPort)
378400
: super(parent, appInjector, parent._node, parent._nodeAttrs, eventHandler, scope,
379401
parent._animate);
380402

@@ -386,56 +408,16 @@ abstract class ComponentDirectiveInjector extends DirectiveInjector {
386408
}
387409
}
388410

389-
_getDirectiveByKey(Key k, int visType, Injector i) =>
390-
super._getDirectiveByKey(k, visType + VISIBILITY_COMPONENT_OFFSET, i);
391-
}
392-
393-
class ShadowlessComponentDirectiveInjector extends ComponentDirectiveInjector {
394-
final ContentPort _contentPort;
395-
396-
ShadowlessComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
397-
EventHandler eventHandler, Scope scope,
398-
templateLoader, shadowRoot, this._contentPort)
399-
: super(parent, appInjector, eventHandler, scope, templateLoader, shadowRoot);
400-
401-
Object _getById(int keyId) {
402-
switch(keyId) {
403-
case CONTENT_PORT_KEY_ID: return _contentPort;
404-
default: return super._getById(keyId);
405-
}
406-
}
407-
}
408-
409-
class ShadowDomComponentDirectiveInjector extends ComponentDirectiveInjector {
410-
ShadowDomComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
411-
Scope scope, templateLoader, shadowRoot)
412-
: super(parent, appInjector, new ShadowRootEventHandler(shadowRoot,
413-
parent.getByKey(EXPANDO_KEY),
414-
parent.getByKey(EXCEPTION_HANDLER_KEY)),
415-
scope, templateLoader, shadowRoot);
416-
417411
ElementProbe get elementProbe {
418412
if (_elementProbe == null) {
419413
ElementProbe parentProbe = _parent == null ? null : _parent.elementProbe;
420414
_elementProbe = new ElementProbe(parentProbe, _shadowRoot, this, scope);
421415
}
422416
return _elementProbe;
423417
}
424-
}
425418

426-
@Injectable()
427-
class DefaultDirectiveInjector extends DirectiveInjector {
428-
DefaultDirectiveInjector(Injector appInjector): super._default(null, appInjector);
429-
DefaultDirectiveInjector.newAppInjector(DirectiveInjector parent, Injector appInjector)
430-
: super._default(parent, appInjector);
431-
432-
Object getByKey(Key key) => appInjector.getByKey(key);
433-
_getDirectiveByKey(Key key, int visType, Injector i) =>
434-
_parent == null ? i.getByKey(key) : _parent._getDirectiveByKey(key, visType, i);
435-
_getById(int keyId) {
436-
switch (keyId) {
437-
case CONTENT_PORT_KEY_ID: return null;
438-
default: throw new NoProviderError(DirectiveInjector._KEYS[keyId]);
439-
}
440-
}
419+
// Add 1 to visibility to allow to skip over current component injector.
420+
// For example, a local directive is visible from its component injector children.
421+
num _getDepth(int visType) => super._getDepth(visType) + 1;
441422
}
423+

lib/core_dom/directive_map.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ class DirectiveMap {
1313
final 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 dir) {
@@ -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) {

0 commit comments

Comments
 (0)