Skip to content

Commit 74f9fbe

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 dart-archive#1111
1 parent 916bc6e commit 74f9fbe

33 files changed

+357
-259
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

+92-111
Large diffs are not rendered by default.

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
}

lib/core_dom/module_internal.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ class CoreDomModule extends Module {
6262
bind(TemplateCache, toFactory: (CacheRegister register) {
6363
var templateCache = new TemplateCache();
6464
register.registerCache("TemplateCache", templateCache);
65-
return templateCache;
66-
}, inject: [CACHE_REGISTER_KEY]);
65+
return templateCache; }, inject: [CACHE_REGISTER_KEY]);
6766
bind(dom.NodeTreeSanitizer, toImplementation: NullTreeSanitizer);
6867

6968
bind(TextMustache);
@@ -96,5 +95,8 @@ class CoreDomModule extends Module {
9695
bind(ElementBinderFactory);
9796
bind(NgElement);
9897
bind(EventHandler);
98+
// TODO(rkirov): remove this once clients have stopped relying on it.
99+
bind(DirectiveInjector, toValue: null);
100+
99101
}
100102
}

lib/core_dom/selector.dart

+14-8
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ class DirectiveSelector {
2626
Interpolate _interpolate;
2727
FormatterMap _formatters;
2828
ASTParser _astParser;
29+
final Injector _injector;
2930
var elementSelector = new _ElementSelector('');
3031
var attrSelector = <_ContainsSelector>[];
3132
var textSelector = <_ContainsSelector>[];
3233

3334
/// Parses all the [_directives] so they can be retrieved via [matchElement]
34-
DirectiveSelector(this._directives, this._formatters, this._binderFactory, this._interpolate, this._astParser) {
35+
DirectiveSelector(this._directives, this._formatters, this._binderFactory, this._interpolate,
36+
this._astParser, this._injector) {
3537
_directives.forEach((Directive annotation, Type type) {
3638
var match;
3739
var selector = annotation.selector;
@@ -59,7 +61,7 @@ class DirectiveSelector {
5961
ElementBinder matchElement(dom.Node node) {
6062
assert(node is dom.Element);
6163

62-
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);
64+
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives, _injector);
6365
List<_ElementSelector> partialSelection;
6466
final classes = new Set<String>();
6567
final attrs = new HashMap<String, String>();
@@ -129,7 +131,7 @@ class DirectiveSelector {
129131
}
130132

131133
ElementBinder matchText(dom.Node node) {
132-
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives);
134+
ElementBinderBuilder builder = _binderFactory.builder(_formatters, _directives, _injector);
133135

134136
var value = node.nodeValue;
135137
for (var k = 0; k < textSelector.length; k++) {
@@ -148,7 +150,7 @@ class DirectiveSelector {
148150
return builder.binder;
149151
}
150152

151-
ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null, null).binder;
153+
ElementBinder matchComment(dom.Node node) => _binderFactory.builder(null, null, _injector).binder;
152154
}
153155

154156
/**
@@ -162,19 +164,23 @@ class DirectiveSelectorFactory {
162164
// TODO(deboer): Remove once the FormatterMap is a required 'selector' parameter.
163165
FormatterMap _defaultFormatterMap;
164166

167+
// TODO(rkirov): Remove once the injector is a required 'selector' parameter.
168+
Injector _defaultInjector;
169+
165170
DirectiveSelectorFactory(this._binderFactory, this._interpolate,
166-
this._astParser, this._defaultFormatterMap);
171+
this._astParser, this._defaultFormatterMap, this._defaultInjector);
167172

168173
/**
169174
* Create a new [DirectiveSelector] given a [DirectiveMap] and [FormatterMap]
170175
*
171-
* NOTE: [formatters] will become required very soon. New code must pass
176+
* NOTE: [injector and formatters] will become required very soon. New code must pass
172177
* both parameters.
173178
*/
174-
DirectiveSelector selector(DirectiveMap directives, [FormatterMap formatters]) =>
179+
DirectiveSelector selector(DirectiveMap directives, [Injector injector, FormatterMap formatters]) =>
175180
new DirectiveSelector(directives,
176181
formatters != null ? formatters : _defaultFormatterMap,
177-
_binderFactory, _interpolate, _astParser);
182+
_binderFactory, _interpolate, _astParser,
183+
injector != null ? injector : _defaultInjector);
178184
}
179185

180186
class _Directive {

lib/core_dom/shadow_dom_component_factory.dart

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
part of angular.core.dom_internal;
22

33
abstract class ComponentFactory {
4-
BoundComponentFactory bind(DirectiveRef ref, directives);
4+
BoundComponentFactory bind(DirectiveRef ref, directives, Injector injector);
55
}
66

77
/**
@@ -52,23 +52,24 @@ class ShadowDomComponentFactory implements ComponentFactory {
5252
cacheRegister.registerCache("ShadowDomComponentFactoryStyles", styleElementCache);
5353
}
5454

55-
bind(DirectiveRef ref, directives) =>
56-
new BoundShadowDomComponentFactory(this, ref, directives);
55+
bind(DirectiveRef ref, directives, injector) =>
56+
new BoundShadowDomComponentFactory(this, ref, directives, injector);
5757
}
5858

5959
class BoundShadowDomComponentFactory implements BoundComponentFactory {
6060

6161
final ShadowDomComponentFactory _f;
6262
final DirectiveRef _ref;
6363
final DirectiveMap _directives;
64+
final Injector _injector;
6465

6566
Component get _component => _ref.annotation as Component;
6667

6768
String _tag;
6869
async.Future<Iterable<dom.StyleElement>> _styleElementsFuture;
6970
async.Future<ViewFactory> _viewFuture;
7071

71-
BoundShadowDomComponentFactory(this._f, this._ref, this._directives) {
72+
BoundShadowDomComponentFactory(this._f, this._ref, this._directives, this._injector) {
7273
_tag = _component.selector.toLowerCase();
7374
_styleElementsFuture = async.Future.wait(_component.cssUrls.map(_styleFuture));
7475

@@ -164,8 +165,10 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
164165
}));
165166

166167
var probe;
167-
shadowInjector = new ShadowDomComponentDirectiveInjector(injector, injector.appInjector,
168-
shadowScope, templateLoader, shadowDom);
168+
var shadowEventHandler = new ShadowRootEventHandler(
169+
shadowDom, injector.getByKey(EXPANDO_KEY), injector.getByKey(EXCEPTION_HANDLER_KEY));
170+
shadowInjector = new ComponentDirectiveInjector(injector, this._injector, shadowEventHandler,
171+
shadowScope, templateLoader, shadowDom, null);
169172
shadowInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys, _ref.annotation.visibility);
170173

171174
if (_f.config.elementProbeEnabled) {

lib/core_dom/tagging_view_factory.dart

+10-13
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,9 @@ class TaggingViewFactory implements ViewFactory {
6666
var timerId;
6767
try {
6868
assert((timerId = _perf.startTimer('ng.view')) != false);
69-
Animate animate = directiveInjector.getByKey(ANIMATE_KEY);
70-
EventHandler eventHandler = directiveInjector.getByKey(EVENT_HANDLER_KEY);
71-
var view = new View(nodes, scope, eventHandler);
72-
_link(view, scope, nodes, eventHandler, animate, directiveInjector);
69+
70+
var view = new View(nodes, scope);
71+
_link(view, scope, nodes, directiveInjector);
7372
return view;
7473
} finally {
7574
assert(_perf.stopTimer(timerId) != false);
@@ -78,8 +77,7 @@ class TaggingViewFactory implements ViewFactory {
7877

7978
void _bindTagged(TaggedElementBinder tagged, int elementBinderIndex,
8079
DirectiveInjector rootInjector,
81-
List<DirectiveInjector> elementInjectors, View view, boundNode, Scope scope,
82-
EventHandler eventHandler, Animate animate) {
80+
List<DirectiveInjector> elementInjectors, View view, boundNode, Scope scope) {
8381
var binder = tagged.binder;
8482
DirectiveInjector parentInjector =
8583
tagged.parentBinderOffset == -1 ? rootInjector : elementInjectors[tagged.parentBinderOffset];
@@ -92,7 +90,7 @@ class TaggingViewFactory implements ViewFactory {
9290
if (parentInjector != rootInjector && parentInjector.scope != null) {
9391
scope = parentInjector.scope;
9492
}
95-
elementInjector = binder.bind(view, scope, parentInjector, boundNode, eventHandler, animate);
93+
elementInjector = binder.bind(view, scope, parentInjector, boundNode);
9694
}
9795
// TODO(misko): Remove this after we remove controllers. No controllers -> 1to1 Scope:View.
9896
if (elementInjector != rootInjector && elementInjector.scope != null) {
@@ -104,13 +102,12 @@ class TaggingViewFactory implements ViewFactory {
104102
for (var k = 0; k < tagged.textBinders.length; k++) {
105103
TaggedTextBinder taggedText = tagged.textBinders[k];
106104
var childNode = boundNode.childNodes[taggedText.offsetIndex];
107-
taggedText.binder.bind(view, scope, elementInjector, childNode, eventHandler, animate);
105+
taggedText.binder.bind(view, scope, elementInjector, childNode);
108106
}
109107
}
110108
}
111109

112-
View _link(View view, Scope scope, List<dom.Node> nodeList, EventHandler eventHandler,
113-
Animate animate, DirectiveInjector rootInjector) {
110+
View _link(View view, Scope scope, List<dom.Node> nodeList, DirectiveInjector rootInjector) {
114111
var elementInjectors = new List<DirectiveInjector>(elementBinders.length);
115112
var directiveDefsByName = {};
116113

@@ -132,7 +129,7 @@ class TaggingViewFactory implements ViewFactory {
132129
if (linkingInfo.containsNgBinding) {
133130
var tagged = elementBinders[elementBinderIndex];
134131
_bindTagged(tagged, elementBinderIndex, rootInjector,
135-
elementInjectors, view, node, scope, eventHandler, animate);
132+
elementInjectors, view, node, scope);
136133
elementBinderIndex++;
137134
}
138135

@@ -141,15 +138,15 @@ class TaggingViewFactory implements ViewFactory {
141138
for (int j = 0; j < elts.length; j++, elementBinderIndex++) {
142139
TaggedElementBinder tagged = elementBinders[elementBinderIndex];
143140
_bindTagged(tagged, elementBinderIndex, rootInjector, elementInjectors,
144-
view, elts[j], scope, eventHandler, animate);
141+
view, elts[j], scope);
145142
}
146143
}
147144
} else {
148145
TaggedElementBinder tagged = elementBinders[elementBinderIndex];
149146
assert(tagged.binder != null || tagged.isTopLevel);
150147
if (tagged.binder != null) {
151148
_bindTagged(tagged, elementBinderIndex, rootInjector,
152-
elementInjectors, view, node, scope, eventHandler, animate);
149+
elementInjectors, view, node, scope);
153150
}
154151
elementBinderIndex++;
155152
}

0 commit comments

Comments
 (0)