feat(ElementInjector): support an arbitrary number of bindings

fixes #1853
This commit is contained in:
Victor Berchet 2015-05-20 17:26:22 +02:00
parent 588fbfd848
commit b1c9bf14b2
2 changed files with 1068 additions and 837 deletions

File diff suppressed because it is too large Load Diff

View File

@ -211,6 +211,13 @@ export function main() {
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null); var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null);
var appInjector = Injector.resolveAndCreate([]); var appInjector = Injector.resolveAndCreate([]);
// An injector with more than 10 bindings will switch to the dynamic strategy
var dynamicBindings = [];
for (var i = 0; i < 20; i++) {
ListWrapper.push(dynamicBindings, bind(i).toValue(i));
}
function createPei(parent, index, bindings, distance = 1, hasShadowRoot = false) { function createPei(parent, index, bindings, distance = 1, hasShadowRoot = false) {
var directiveBinding = ListWrapper.map(bindings, b => { var directiveBinding = ListWrapper.map(bindings, b => {
if (b instanceof DirectiveBinding) return b; if (b instanceof DirectiveBinding) return b;
@ -350,8 +357,6 @@ export function main() {
}); });
}); });
describe("ProtoElementInjector", () => { describe("ProtoElementInjector", () => {
describe("direct parent", () => { describe("direct parent", () => {
it("should return parent proto injector when distance is 1", () => { it("should return parent proto injector when distance is 1", () => {
@ -370,10 +375,11 @@ export function main() {
expect(protoChild.directParent()).toEqual(null); expect(protoChild.directParent()).toEqual(null);
}); });
it("should allow for direct access using getBindingAtIndex", function () { });
var binding = DirectiveBinding.createFromBinding(
bind(SimpleDirective).toClass(SimpleDirective), null); describe('inline strategy', () => {
var proto = createPei(null, 0, [binding]); it("should allow for direct access using getBindingAtIndex", () => {
var proto = createPei(null, 0, [bind(SimpleDirective).toClass(SimpleDirective)]);
expect(proto.getBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding); expect(proto.getBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding);
expect(() => proto.getBindingAtIndex(-1)).toThrowError( expect(() => proto.getBindingAtIndex(-1)).toThrowError(
@ -383,6 +389,19 @@ export function main() {
}); });
}); });
describe('dynamic strategy', () => {
it("should allow for direct access using getBindingAtIndex", () => {
var proto = createPei(null, 0, dynamicBindings);
expect(proto.getBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding);
expect(() => proto.getBindingAtIndex(-1)).toThrowError(
'Index -1 is out-of-bounds.');
expect(() => proto.getBindingAtIndex(dynamicBindings.length - 1)).not.toThrow();
expect(() => proto.getBindingAtIndex(dynamicBindings.length)).toThrowError(
`Index ${dynamicBindings.length} is out-of-bounds.`);
});
});
describe('event emitters', () => { describe('event emitters', () => {
it('should return a list of event accessors', () => { it('should return a list of event accessors', () => {
var binding = DirectiveBinding.createFromType( var binding = DirectiveBinding.createFromType(
@ -434,12 +453,21 @@ export function main() {
expect(pei.getBindingAtIndex(0).key.token).toBe(SimpleDirective); expect(pei.getBindingAtIndex(0).key.token).toBe(SimpleDirective);
expect(pei.getBindingAtIndex(1).key.token).toEqual("injectable1"); expect(pei.getBindingAtIndex(1).key.token).toEqual("injectable1");
}); });
it('should support an arbitrary number of bindings', () => {
var pei = createPei(null, 0, dynamicBindings);
for (var i = 0; i < dynamicBindings.length; i++) {
expect(pei.getBindingAtIndex(i).key.token).toBe(i);
}
}); });
}); });
describe("ElementInjector", function () { });
describe("instantiate", function () {
it("should create an element injector", function () { describe("ElementInjector", () => {
describe("instantiate", () => {
it("should create an element injector", () => {
var protoParent = createPei(null, 0, []); var protoParent = createPei(null, 0, []);
var protoChild1 = createPei(protoParent, 1, []); var protoChild1 = createPei(protoParent, 1, []);
var protoChild2 = createPei(protoParent, 2, []); var protoChild2 = createPei(protoParent, 2, []);
@ -480,36 +508,44 @@ export function main() {
}); });
}); });
describe("hasBindings", function () { describe("hasBindings", () => {
it("should be true when there are bindings", function () { it("should be true when there are bindings", () => {
var p = createPei(null, 0, [SimpleDirective]); var p = createPei(null, 0, [SimpleDirective]);
expect(p.hasBindings).toBeTruthy(); expect(p.hasBindings).toBeTruthy();
}); });
it("should be false otherwise", function () { it("should be false otherwise", () => {
var p = createPei(null, 0, []); var p = createPei(null, 0, []);
expect(p.hasBindings).toBeFalsy(); expect(p.hasBindings).toBeFalsy();
}); });
}); });
describe("hasInstances", function () { describe("hasInstances", () => {
it("should be false when no directives are instantiated", function () { it("should be false when no directives are instantiated", () => {
expect(injector([]).hasInstances()).toBe(false); expect(injector([]).hasInstances()).toBe(false);
}); });
it("should be true when directives are instantiated", function () { it("should be true when directives are instantiated", () => {
expect(injector([SimpleDirective]).hasInstances()).toBe(true); expect(injector([SimpleDirective]).hasInstances()).toBe(true);
}); });
}); });
describe("hydrate", function () { [
it("should instantiate directives that have no dependencies", function () { { strategy: 'inline', bindings: []},
var inj = injector([SimpleDirective]); { strategy: 'dynamic', bindings: dynamicBindings}
].forEach((context) => {
var extraBindings = context['bindings'];
describe(`${context['strategy']} strategy`, () => {
describe("hydrate", () => {
it("should instantiate directives that have no dependencies", () => {
var bindings = ListWrapper.concat([SimpleDirective], extraBindings);
var inj = injector(bindings);
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective); expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
}); });
it("should instantiate directives that depend on other directives", function () { it("should instantiate directives that depend on an arbitrary number of directives", () => {
var inj = injector([SimpleDirective, NeedsDirective]); var bindings = ListWrapper.concat([SimpleDirective, NeedsDirective], extraBindings);
var inj = injector(bindings);
var d = inj.get(NeedsDirective); var d = inj.get(NeedsDirective);
@ -517,24 +553,14 @@ export function main() {
expect(d.dependency).toBeAnInstanceOf(SimpleDirective); expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}); });
it("should instantiate hostInjector injectables that have dependencies", function () {
var inj = injector([
DirectiveBinding.createFromType(SimpleDirective,
new DummyDirective({hostInjector: [
bind('injectable1').toValue('injectable1'),
bind('injectable2').toFactory((val) => `${val}-injectable2`, ['injectable1'])
]}))
]);
expect(inj.get('injectable2')).toEqual('injectable1-injectable2');
});
it("should instantiate hostInjector injectables that have dependencies with set visibility", function () { it("should instantiate hostInjector injectables that have dependencies with set visibility", function () {
var childInj= parentChildInjectors([ var childInj= parentChildInjectors(ListWrapper.concat([
DirectiveBinding.createFromType(SimpleDirective, DirectiveBinding.createFromType(SimpleDirective,
new DummyDirective({hostInjector: [ new DummyDirective({hostInjector: [
bind('injectable1').toValue('injectable1') bind('injectable1').toValue('injectable1')
]})) ]}))
], [ ], extraBindings), [
DirectiveBinding.createFromType(SimpleDirective, DirectiveBinding.createFromType(SimpleDirective,
new DummyDirective({hostInjector: [ new DummyDirective({hostInjector: [
bind('injectable1').toValue('new-injectable1'), bind('injectable1').toValue('new-injectable1'),
@ -554,10 +580,32 @@ export function main() {
expect(inj.get(NeedsService).service).toEqual('service'); expect(inj.get(NeedsService).service).toEqual('service');
}); });
it("should instantiate directives that depend on app services", function () { it("should instantiate hostInjector injectables that have dependencies", () => {
var appInjector = Injector.resolveAndCreate([ var inj = injector(ListWrapper.concat([
bind("service").toValue("service") DirectiveBinding.createFromType(SimpleDirective,
]); new DummyDirective({hostInjector: [
bind('injectable1').toValue('injectable1'),
bind('injectable2').toFactory((val) => `${val}-injectable2`, ['injectable1'])
]}))],
extraBindings
));
expect(inj.get('injectable2')).toEqual('injectable1-injectable2');
});
it("should instantiate components that depends on viewInjector dependencies", function () {
var inj = injector(ListWrapper.concat([
DirectiveBinding.createFromType(NeedsService,
new DummyDirective({viewInjector: [
bind('service').toValue('service')
]}))],
extraBindings),
null, true);
expect(inj.get(NeedsService).service).toEqual('service');
});
it("should instantiate directives that depend on app services", () => {
var appInjector = Injector.resolveAndCreate(ListWrapper.concat([
bind("service").toValue("service")], extraBindings));
var inj = injector([NeedsService], appInjector); var inj = injector([NeedsService], appInjector);
var d = inj.get(NeedsService); var d = inj.get(NeedsService);
@ -565,24 +613,27 @@ export function main() {
expect(d.service).toEqual("service"); expect(d.service).toEqual("service");
}); });
it("should instantiate directives that depend on pre built objects", function () { it("should instantiate directives that depend on pre built objects", () => {
var protoView = new AppProtoView(null, null, null); var protoView = new AppProtoView(null, null, null);
var inj = injector([NeedsProtoViewRef], null, false, new PreBuiltObjects(null, null, protoView)); var bindings = ListWrapper.concat([NeedsProtoViewRef], extraBindings);
var inj = injector(bindings, null, false, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
}); });
it("should return app services", function () { it("should return app services", () => {
var appInjector = Injector.resolveAndCreate([ var appInjector = Injector.resolveAndCreate(ListWrapper.concat([
bind("service").toValue("service") bind("service").toValue("service")], extraBindings
]); ));
var inj = injector([], appInjector); var inj = injector([], appInjector);
expect(inj.get('service')).toEqual('service'); expect(inj.get('service')).toEqual('service');
}); });
it("should get directives from parent", function () { it("should get directives from parent", () => {
var child = parentChildInjectors([SimpleDirective], [NeedsDirectiveFromParent]); var child = parentChildInjectors(
ListWrapper.concat([SimpleDirective], extraBindings),
[NeedsDirectiveFromParent]);
var d = child.get(NeedsDirectiveFromParent); var d = child.get(NeedsDirectiveFromParent);
@ -590,14 +641,17 @@ export function main() {
expect(d.dependency).toBeAnInstanceOf(SimpleDirective); expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}); });
it("should not return parent's directives on self", function () { it("should not return parent's directives on self", () => {
expect(() => { expect(() => {
injector([SimpleDirective, NeedsDirectiveFromParent]); injector(ListWrapper.concat(
[SimpleDirective, NeedsDirectiveFromParent], extraBindings));
}).toThrowError(new RegExp("No provider for SimpleDirective")); }).toThrowError(new RegExp("No provider for SimpleDirective"));
}); });
it("should get directives from ancestor", function () { it("should get directives from ancestor", () => {
var child = parentChildInjectors([SimpleDirective], [NeedsDirectiveFromAncestor]); var child = parentChildInjectors(
ListWrapper.concat([SimpleDirective], extraBindings),
[NeedsDirectiveFromAncestor]);
var d = child.get(NeedsDirectiveFromAncestor); var d = child.get(NeedsDirectiveFromAncestor);
@ -605,8 +659,9 @@ export function main() {
expect(d.dependency).toBeAnInstanceOf(SimpleDirective); expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}); });
it("should get directives crossing the boundaries", function () { it("should get directives crossing the boundaries", () => {
var child = hostShadowInjectors([SomeOtherDirective, SimpleDirective], var child = hostShadowInjectors(
ListWrapper.concat([SomeOtherDirective, SimpleDirective], extraBindings),
[NeedsDirectiveFromAnAncestorShadowDom]); [NeedsDirectiveFromAnAncestorShadowDom]);
var d = child.get(NeedsDirectiveFromAnAncestorShadowDom); var d = child.get(NeedsDirectiveFromAnAncestorShadowDom);
@ -615,52 +670,59 @@ export function main() {
expect(d.dependency).toBeAnInstanceOf(SimpleDirective); expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
}); });
it("should throw when a depenency cannot be resolved", function () { it("should throw when a depenency cannot be resolved", () => {
expect(() => injector([NeedsDirectiveFromParent])). expect(() => injector(ListWrapper.concat([NeedsDirectiveFromParent], extraBindings))).
toThrowError('No provider for SimpleDirective! (NeedsDirectiveFromParent -> SimpleDirective)'); toThrowError('No provider for SimpleDirective! (NeedsDirectiveFromParent -> SimpleDirective)');
}); });
it("should inject null when an optional dependency cannot be resolved", function () { it("should inject null when an optional dependency cannot be resolved", () => {
var inj = injector([OptionallyNeedsDirective]); var inj = injector(ListWrapper.concat([OptionallyNeedsDirective], extraBindings));
var d = inj.get(OptionallyNeedsDirective); var d = inj.get(OptionallyNeedsDirective);
expect(d.dependency).toEqual(null); expect(d.dependency).toEqual(null);
}); });
it("should accept bindings instead types", function () { it("should accept bindings instead types", () => {
var inj = injector([ var inj = injector(ListWrapper.concat([
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null) bind(SimpleDirective).toClass(SimpleDirective)],
]); extraBindings
));
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective); expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
}); });
it("should allow for direct access using getDirectiveAtIndex", function () { it("should allow for direct access using getDirectiveAtIndex", () => {
var inj = injector([ var bindings = ListWrapper.concat([
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null) bind(SimpleDirective).toClass(SimpleDirective)],
]); extraBindings
);
var inj = injector(bindings);
var firsIndexOut = bindings.length > 10 ? bindings.length : 10;
expect(inj.getDirectiveAtIndex(0)).toBeAnInstanceOf(SimpleDirective); expect(inj.getDirectiveAtIndex(0)).toBeAnInstanceOf(SimpleDirective);
expect(() => inj.getDirectiveAtIndex(-1)).toThrowError( expect(() => inj.getDirectiveAtIndex(-1)).toThrowError(
'Index -1 is out-of-bounds.'); 'Index -1 is out-of-bounds.');
expect(() => inj.getDirectiveAtIndex(10)).toThrowError( expect(() => inj.getDirectiveAtIndex(firsIndexOut)).toThrowError(
'Index 10 is out-of-bounds.'); `Index ${firsIndexOut} is out-of-bounds.`);
}); });
it("should handle cyclic dependencies", function () { it("should handle cyclic dependencies", () => {
expect(() => { expect(() => {
var bAneedsB = bind(A_Needs_B).toFactory((a) => new A_Needs_B(a), [B_Needs_A]); var bAneedsB = bind(A_Needs_B).toFactory((a) => new A_Needs_B(a), [B_Needs_A]);
var bBneedsA = bind(B_Needs_A).toFactory((a) => new B_Needs_A(a), [A_Needs_B]); var bBneedsA = bind(B_Needs_A).toFactory((a) => new B_Needs_A(a), [A_Needs_B]);
injector([
DirectiveBinding.createFromBinding(bAneedsB, null), injector(ListWrapper.concat([bAneedsB, bBneedsA], extraBindings));
DirectiveBinding.createFromBinding(bBneedsA, null)
]);
}).toThrowError('Cannot instantiate cyclic dependency! ' + }).toThrowError('Cannot instantiate cyclic dependency! ' +
'(A_Needs_B -> B_Needs_A -> A_Needs_B)'); '(A_Needs_B -> B_Needs_A -> A_Needs_B)');
}); });
describe("shadow DOM components", () => { describe("shadow DOM components", () => {
it("should instantiate directives that depend on the containing component", function () { it("should instantiate directives that depend on the containing component", () => {
var directiveBinding = DirectiveBinding.createFromType(SimpleDirective, new Component()); var directiveBinding = DirectiveBinding.createFromType(SimpleDirective, new Component());
var shadow = hostShadowInjectors([directiveBinding], [NeedsDirective]); var shadow = hostShadowInjectors(
ListWrapper.concat([directiveBinding], extraBindings),
[NeedsDirective]);
var d = shadow.get(NeedsDirective); var d = shadow.get(NeedsDirective);
expect(d).toBeAnInstanceOf(NeedsDirective); expect(d).toBeAnInstanceOf(NeedsDirective);
@ -670,15 +732,18 @@ export function main() {
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => { it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
var directiveBinding = DirectiveBinding.createFromType(SomeOtherDirective, new Component()); var directiveBinding = DirectiveBinding.createFromType(SomeOtherDirective, new Component());
expect(() => { expect(() => {
hostShadowInjectors([directiveBinding, SimpleDirective],[NeedsDirective]); hostShadowInjectors(
ListWrapper.concat([directiveBinding, SimpleDirective], extraBindings),
[NeedsDirective]);
}).toThrowError('No provider for SimpleDirective! (NeedsDirective -> SimpleDirective)'); }).toThrowError('No provider for SimpleDirective! (NeedsDirective -> SimpleDirective)');
}); });
it("should instantiate component directives that depend on app services in the shadow app injector", () => { it("should instantiate component directives that depend on app services in the shadow app injector", () => {
var directiveAnnotation = new Component({ var directiveAnnotation = new Component({
appInjector: [ appInjector: ListWrapper.concat([
bind("service").toValue("service") bind("service").toValue("service")],
] extraBindings
)
}); });
var componentDirective = DirectiveBinding.createFromType( var componentDirective = DirectiveBinding.createFromType(
NeedsService, directiveAnnotation); NeedsService, directiveAnnotation);
@ -691,9 +756,10 @@ export function main() {
it("should not instantiate other directives that depend on app services in the shadow app injector", () => { it("should not instantiate other directives that depend on app services in the shadow app injector", () => {
var directiveAnnotation = new Component({ var directiveAnnotation = new Component({
appInjector: [ appInjector: ListWrapper.concat([
bind("service").toValue("service") bind("service").toValue("service")],
] extraBindings
)
}); });
var componentDirective = DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation); var componentDirective = DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation);
expect(() => { expect(() => {
@ -705,21 +771,27 @@ export function main() {
describe("lifecycle", () => { describe("lifecycle", () => {
it("should call onDestroy on directives subscribed to this event", function() { it("should call onDestroy on directives subscribed to this event", function() {
var inj = injector([DirectiveBinding.createFromType(DirectiveWithDestroy, new DummyDirective({lifecycle: [onDestroy]}))]); var inj = injector(ListWrapper.concat([
DirectiveBinding.createFromType(DirectiveWithDestroy, new DummyDirective({lifecycle: [onDestroy]}))],
extraBindings
));
var destroy = inj.get(DirectiveWithDestroy); var destroy = inj.get(DirectiveWithDestroy);
inj.dehydrate(); inj.dehydrate();
expect(destroy.onDestroyCounter).toBe(1); expect(destroy.onDestroyCounter).toBe(1);
}); });
it("should work with services", function() { it("should work with services", function() {
var inj = injector([DirectiveBinding.createFromType(SimpleDirective, new DummyDirective({hostInjector: [SimpleService]}))]); var inj = injector(ListWrapper.concat([
DirectiveBinding.createFromType(SimpleDirective, new DummyDirective({hostInjector: [SimpleService]}))],
extraBindings
));
inj.dehydrate(); inj.dehydrate();
}); });
}); });
describe("dynamicallyCreateComponent", () => { describe("dynamicallyCreateComponent", () => {
it("should create a component dynamically", () => { it("should create a component dynamically", () => {
var inj = injector([]); var inj = injector(extraBindings);
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(SimpleDirective, null), appInjector); inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(SimpleDirective, null), appInjector);
expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(SimpleDirective); expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(SimpleDirective);
@ -727,7 +799,9 @@ export function main() {
}); });
it("should inject parent dependencies into the dynamically-loaded component", () => { it("should inject parent dependencies into the dynamically-loaded component", () => {
var inj = parentChildInjectors([SimpleDirective], []); var inj = parentChildInjectors(
ListWrapper.concat([SimpleDirective], extraBindings),
[]);
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedsDirectiveFromAncestor, null), appInjector); inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedsDirectiveFromAncestor, null), appInjector);
expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(NeedsDirectiveFromAncestor); expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
expect(inj.getDynamicallyLoadedComponent().dependency).toBeAnInstanceOf(SimpleDirective); expect(inj.getDynamicallyLoadedComponent().dependency).toBeAnInstanceOf(SimpleDirective);
@ -737,7 +811,8 @@ export function main() {
var injWithDynamicallyLoadedComponent = injector([SimpleDirective]); var injWithDynamicallyLoadedComponent = injector([SimpleDirective]);
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(DirectiveBinding.createFromType(SomeOtherDirective, null), appInjector); injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(DirectiveBinding.createFromType(SomeOtherDirective, null), appInjector);
var shadowDomProtoInjector = createPei(null, 0, [NeedsDirectiveFromAncestor]); var shadowDomProtoInjector = createPei(
null, 0, ListWrapper.concat([NeedsDirectiveFromAncestor], extraBindings));
var shadowDomInj = shadowDomProtoInjector.instantiate(null); var shadowDomInj = shadowDomProtoInjector.instantiate(null);
expect(() => expect(() =>
@ -747,7 +822,8 @@ export function main() {
it("should not inject the dynamically-loaded component into directives on the same element", () => { it("should not inject the dynamically-loaded component into directives on the same element", () => {
var dynamicComp = DirectiveBinding.createFromType(SomeOtherDirective, new Component()); var dynamicComp = DirectiveBinding.createFromType(SomeOtherDirective, new Component());
var proto = createPei(null, 0, [dynamicComp, NeedsDirective], 1, true); var proto = createPei(
null, 0, ListWrapper.concat([dynamicComp, NeedsDirective], extraBindings), 1, true);
var inj = proto.instantiate(null); var inj = proto.instantiate(null);
inj.dynamicallyCreateComponent( inj.dynamicallyCreateComponent(
DirectiveBinding.createFromType(SimpleDirective, null), appInjector); DirectiveBinding.createFromType(SimpleDirective, null), appInjector);
@ -767,7 +843,8 @@ export function main() {
var injWithDynamicallyLoadedComponent = injector([]); var injWithDynamicallyLoadedComponent = injector([]);
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(componentDirective, appInjector); injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(componentDirective, appInjector);
var shadowDomProtoInjector = createPei(null, 0, [NeedsDirectiveFromAncestor]); var shadowDomProtoInjector = createPei(
null, 0, ListWrapper.concat([NeedsDirectiveFromAncestor], extraBindings));
var shadowDomInjector = shadowDomProtoInjector.instantiate(null); var shadowDomInjector = shadowDomProtoInjector.instantiate(null);
shadowDomInjector.hydrate(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects); shadowDomInjector.hydrate(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects);
@ -776,7 +853,7 @@ export function main() {
}); });
it("should remove the dynamically-loaded component when dehydrating", () => { it("should remove the dynamically-loaded component when dehydrating", () => {
var inj = injector([]); var inj = injector(extraBindings);
inj.dynamicallyCreateComponent( inj.dynamicallyCreateComponent(
DirectiveBinding.createFromType( DirectiveBinding.createFromType(
DirectiveWithDestroy, DirectiveWithDestroy,
@ -796,7 +873,7 @@ export function main() {
}); });
it("should inject services of the dynamically-loaded component", () => { it("should inject services of the dynamically-loaded component", () => {
var inj = injector([]); var inj = injector(extraBindings);
var appInjector = Injector.resolveAndCreate([bind("service").toValue("Service")]); var appInjector = Injector.resolveAndCreate([bind("service").toValue("Service")]);
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedsService, null), appInjector); inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedsService, null), appInjector);
expect(inj.getDynamicallyLoadedComponent().service).toEqual("Service"); expect(inj.getDynamicallyLoadedComponent().service).toEqual("Service");
@ -809,7 +886,8 @@ export function main() {
MapWrapper.set(attributes, 'type', 'text'); MapWrapper.set(attributes, 'type', 'text');
MapWrapper.set(attributes, 'title', ''); MapWrapper.set(attributes, 'title', '');
var inj = injector([NeedsAttribute], null, false, null, attributes); var inj = injector(
ListWrapper.concat([NeedsAttribute], extraBindings), null, false, null, attributes);
var needsAttribute = inj.get(NeedsAttribute); var needsAttribute = inj.get(NeedsAttribute);
expect(needsAttribute.typeAttribute).toEqual('text'); expect(needsAttribute.typeAttribute).toEqual('text');
@ -821,7 +899,8 @@ export function main() {
var attributes = MapWrapper.create(); var attributes = MapWrapper.create();
MapWrapper.set(attributes, 'foo', 'bar'); MapWrapper.set(attributes, 'foo', 'bar');
var inj = injector([NeedsAttributeNoType], null, false, null, attributes); var inj = injector(
ListWrapper.concat([NeedsAttributeNoType], extraBindings), null, false, null, attributes);
var needsAttribute = inj.get(NeedsAttributeNoType); var needsAttribute = inj.get(NeedsAttributeNoType);
expect(needsAttribute.fooAttribute).toEqual('bar'); expect(needsAttribute.fooAttribute).toEqual('bar');
@ -830,41 +909,44 @@ export function main() {
describe("refs", () => { describe("refs", () => {
it("should inject ElementRef", () => { it("should inject ElementRef", () => {
var inj = injector([NeedsElementRef]); var inj = injector(ListWrapper.concat([NeedsElementRef], extraBindings));
expect(inj.get(NeedsElementRef).elementRef).toBeAnInstanceOf(ElementRef); expect(inj.get(NeedsElementRef).elementRef).toBeAnInstanceOf(ElementRef);
}); });
it('should inject ChangeDetectorRef', function () { it('should inject ChangeDetectorRef', () => {
var cd = new DynamicChangeDetector(null, null, null, [], []); var cd = new DynamicChangeDetector(null, null, null, [], []);
var view = new DummyView(); var view = new DummyView();
var childView = new DummyView(); var childView = new DummyView();
childView.changeDetector = cd; childView.changeDetector = cd;
view.componentChildViews = [childView]; view.componentChildViews = [childView];
var inj = injector([NeedsChangeDetectorRef], null, false, new PreBuiltObjects(null, view, null)); var inj = injector(ListWrapper.concat([NeedsChangeDetectorRef], extraBindings),
null, false, new PreBuiltObjects(null, view, null));
expect(inj.get(NeedsChangeDetectorRef).changeDetectorRef).toBe(cd.ref); expect(inj.get(NeedsChangeDetectorRef).changeDetectorRef).toBe(cd.ref);
}); });
it('should inject ViewContainerRef', () => { it('should inject ViewContainerRef', () => {
var inj = injector([NeedsViewContainer]); var inj = injector(ListWrapper.concat([NeedsViewContainer], extraBindings));
expect(inj.get(NeedsViewContainer).viewContainer).toBeAnInstanceOf(ViewContainerRef); expect(inj.get(NeedsViewContainer).viewContainer).toBeAnInstanceOf(ViewContainerRef);
}); });
it("should inject ProtoViewRef", function () { it("should inject ProtoViewRef", () => {
var protoView = new AppProtoView(null, null, null); var protoView = new AppProtoView(null, null, null);
var inj = injector([NeedsProtoViewRef], null, false, new PreBuiltObjects(null, null, protoView)); var inj = injector(ListWrapper.concat([NeedsProtoViewRef], extraBindings),
null, false, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
}); });
it("should throw if there is no ProtoViewRef", function () { it("should throw if there is no ProtoViewRef", () => {
expect( expect(
() => injector([NeedsProtoViewRef]) () => injector(ListWrapper.concat([NeedsProtoViewRef], extraBindings))
).toThrowError('No provider for ProtoViewRef! (NeedsProtoViewRef -> ProtoViewRef)'); ).toThrowError('No provider for ProtoViewRef! (NeedsProtoViewRef -> ProtoViewRef)');
}); });
it('should inject null if there is no ProtoViewRef when the dependency is optional', () => { it('should inject null if there is no ProtoViewRef when the dependency is optional', () => {
var inj = injector([OptionallyInjectsProtoViewRef]); var inj = injector(
ListWrapper.concat([OptionallyInjectsProtoViewRef], extraBindings));
var instance = inj.get(OptionallyInjectsProtoViewRef); var instance = inj.get(OptionallyInjectsProtoViewRef);
expect(instance.protoViewRef).toBeNull(); expect(instance.protoViewRef).toBeNull();
}); });
@ -886,12 +968,14 @@ export function main() {
} }
it('should be injectable', () => { it('should be injectable', () => {
var inj = injector([NeedsQuery], null, false, preBuildObjects); var inj = injector(ListWrapper.concat([NeedsQuery], extraBindings),
null, false, preBuildObjects);
expect(inj.get(NeedsQuery).query).toBeAnInstanceOf(QueryList); expect(inj.get(NeedsQuery).query).toBeAnInstanceOf(QueryList);
}); });
it('should contain directives on the same injector', () => { it('should contain directives on the same injector', () => {
var inj = injector([NeedsQuery, CountingDirective], null, false, preBuildObjects); var inj = injector(ListWrapper.concat([NeedsQuery, CountingDirective], extraBindings),
null, false, preBuildObjects);
expectDirectives(inj.get(NeedsQuery).query, CountingDirective, [0]); expectDirectives(inj.get(NeedsQuery).query, CountingDirective, [0]);
}); });
@ -908,7 +992,8 @@ export function main() {
it('should contain directives on the same and a child injector in construction order', () => { it('should contain directives on the same and a child injector in construction order', () => {
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]); var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
var protoChild = createPei(protoParent, 1, [CountingDirective]); var protoChild = createPei(
protoParent, 1, ListWrapper.concat([CountingDirective], extraBindings));
var parent = protoParent.instantiate(null); var parent = protoParent.instantiate(null);
var child = protoChild.instantiate(parent); var child = protoChild.instantiate(parent);
@ -920,7 +1005,8 @@ export function main() {
it('should reflect unlinking an injector', () => { it('should reflect unlinking an injector', () => {
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]); var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
var protoChild = createPei(protoParent, 1, [CountingDirective]); var protoChild = createPei(protoParent, 1,
ListWrapper.concat([CountingDirective], extraBindings));
var parent = protoParent.instantiate(null); var parent = protoParent.instantiate(null);
var child = protoChild.instantiate(parent); var child = protoChild.instantiate(parent);
@ -935,7 +1021,8 @@ export function main() {
it('should reflect moving an injector as a last child', () => { it('should reflect moving an injector as a last child', () => {
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]); var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
var protoChild1 = createPei(protoParent, 1, [CountingDirective]); var protoChild1 = createPei(protoParent, 1, [CountingDirective]);
var protoChild2 = createPei(protoParent, 1, [CountingDirective]); var protoChild2 = createPei(protoParent, 1,
ListWrapper.concat([CountingDirective], extraBindings));
var parent = protoParent.instantiate(null); var parent = protoParent.instantiate(null);
var child1 = protoChild1.instantiate(parent); var child1 = protoChild1.instantiate(parent);
@ -955,7 +1042,8 @@ export function main() {
it('should reflect moving an injector as a first child', () => { it('should reflect moving an injector as a first child', () => {
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]); var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
var protoChild1 = createPei(protoParent, 1, [CountingDirective]); var protoChild1 = createPei(protoParent, 1, [CountingDirective]);
var protoChild2 = createPei(protoParent, 1, [CountingDirective]); var protoChild2 = createPei(protoParent, 1,
ListWrapper.concat([CountingDirective], extraBindings));
var parent = protoParent.instantiate(null); var parent = protoParent.instantiate(null);
var child1 = protoChild1.instantiate(parent); var child1 = protoChild1.instantiate(parent);
@ -975,7 +1063,8 @@ export function main() {
it('should support two concurrent queries for the same directive', () => { it('should support two concurrent queries for the same directive', () => {
var protoGrandParent = createPei(null, 0, [NeedsQuery]); var protoGrandParent = createPei(null, 0, [NeedsQuery]);
var protoParent = createPei(null, 0, [NeedsQuery]); var protoParent = createPei(null, 0, [NeedsQuery]);
var protoChild = createPei(protoParent, 1, [CountingDirective]); var protoChild = createPei(protoParent, 1,
ListWrapper.concat([CountingDirective], extraBindings));
var grandParent = protoGrandParent.instantiate(null); var grandParent = protoGrandParent.instantiate(null);
var parent = protoParent.instantiate(grandParent); var parent = protoParent.instantiate(grandParent);
@ -997,6 +1086,9 @@ export function main() {
}); });
}); });
}); });
});
});
} }
class ContextWithHandler { class ContextWithHandler {