From c51aef9f7df6975f14a3c049495c72d65d9af47c Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 11 Jun 2015 13:54:17 -0700 Subject: [PATCH] fix(element_injector): changed visibility rules to expose hostInjector of the component to its shadow dom --- .../src/core/compiler/element_injector.ts | 36 ++++++++++--------- .../core/compiler/element_injector_spec.ts | 27 ++++++++++++-- .../test/core/compiler/integration_spec.ts | 35 ++---------------- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/modules/angular2/src/core/compiler/element_injector.ts b/modules/angular2/src/core/compiler/element_injector.ts index 1d9169c816..6bfdd5518b 100644 --- a/modules/angular2/src/core/compiler/element_injector.ts +++ b/modules/angular2/src/core/compiler/element_injector.ts @@ -398,41 +398,45 @@ export class ProtoElementInjector { var bd = []; ProtoElementInjector._createDirectiveBindingData(bindings, bd, firstBindingIsComponent); - ProtoElementInjector._createHostInjectorBindingData(bindings, bd); if (firstBindingIsComponent) { ProtoElementInjector._createViewInjectorBindingData(bindings, bd); } - + ProtoElementInjector._createHostInjectorBindingData(bindings, bd, firstBindingIsComponent); return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent); } - private static _createDirectiveBindingData(bindings: List, bd: List, + private static _createDirectiveBindingData(dirBindings: List, + bd: List, firstBindingIsComponent: boolean) { - if (firstBindingIsComponent) { - ListWrapper.push(bd, new BindingData(bindings[0], LIGHT_DOM_AND_SHADOW_DOM)); - for (var i = 1; i < bindings.length; ++i) { - ListWrapper.push(bd, new BindingData(bindings[i], LIGHT_DOM)); - } - } else { - ListWrapper.forEach(bindings, b => {ListWrapper.push(bd, new BindingData(b, LIGHT_DOM))}); - } + ListWrapper.forEach(dirBindings, dirBinding => { + ListWrapper.push(bd, ProtoElementInjector._createBindingData( + firstBindingIsComponent, dirBinding, dirBindings, dirBinding)); + }); } - private static _createHostInjectorBindingData(bindings: List, - bd: List) { + private static _createHostInjectorBindingData(dirBindings: List, + bd: List, + firstBindingIsComponent: boolean) { var visitedIds: Map = MapWrapper.create(); - ListWrapper.forEach(bindings, b => { - ListWrapper.forEach(b.resolvedHostInjectables, b => { + ListWrapper.forEach(dirBindings, dirBinding => { + ListWrapper.forEach(dirBinding.resolvedHostInjectables, b => { if (MapWrapper.contains(visitedIds, b.key.id)) { throw new BaseException( `Multiple directives defined the same host injectable: "${stringify(b.key.token)}"`); } MapWrapper.set(visitedIds, b.key.id, true); - ListWrapper.push(bd, new BindingData(ProtoElementInjector._createBinding(b), LIGHT_DOM)); + ListWrapper.push(bd, ProtoElementInjector._createBindingData( + firstBindingIsComponent, dirBinding, dirBindings, + ProtoElementInjector._createBinding(b))); }); }); } + private static _createBindingData(firstBindingIsComponent, dirBinding, dirBindings, binding) { + var isComponent = firstBindingIsComponent && dirBindings[0] === dirBinding; + return new BindingData(binding, isComponent ? LIGHT_DOM_AND_SHADOW_DOM : LIGHT_DOM); + } + private static _createViewInjectorBindingData(bindings: List, bd: List) { var db = bindings[0]; diff --git a/modules/angular2/test/core/compiler/element_injector_spec.ts b/modules/angular2/test/core/compiler/element_injector_spec.ts index f708531b9e..fc098214ff 100644 --- a/modules/angular2/test/core/compiler/element_injector_spec.ts +++ b/modules/angular2/test/core/compiler/element_injector_spec.ts @@ -625,15 +625,38 @@ export function main() { expect(inj.get(NeedsService).service).toEqual('service'); }); - it("should prioritize hostInjector over viewInjector for the same binding", () => { + it("should prioritize viewInjector over hostInjector for the same binding", () => { var inj = injector( ListWrapper.concat([DirectiveBinding.createFromType(NeedsService, new dirAnn.Component({ hostInjector: [bind('service').toValue('hostService')], viewInjector: [bind('service').toValue('viewService')]}) )], extraBindings), null, true); - expect(inj.get(NeedsService).service).toEqual('hostService'); + expect(inj.get(NeedsService).service).toEqual('viewService'); }); + it("should instantiate a directive in a view that depends on hostInjector bindings of the component", () => { + var shadowInj = hostShadowInjectors( + ListWrapper.concat([DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({ + hostInjector: [bind('service').toValue('hostService')]}) + )], extraBindings), + ListWrapper.concat([NeedsService], extraBindings) + ); + expect(shadowInj.get(NeedsService).service).toEqual('hostService'); + }); + + it("should not instantiate a directive in a view that depends on hostInjector bindings of a decorator directive", () => { + expect(() => { + hostShadowInjectors( + ListWrapper.concat([ + SimpleDirective, + DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Directive({ + hostInjector: [bind('service').toValue('hostService')]}) + )], extraBindings), + + ListWrapper.concat([NeedsService], extraBindings) + ); + }).toThrowError(new RegExp("No provider for service!")); + }); it("should instantiate directives that depend on app services", () => { var appInjector = Injector.resolveAndCreate( diff --git a/modules/angular2/test/core/compiler/integration_spec.ts b/modules/angular2/test/core/compiler/integration_spec.ts index 65e5460835..6ad5b18911 100644 --- a/modules/angular2/test/core/compiler/integration_spec.ts +++ b/modules/angular2/test/core/compiler/integration_spec.ts @@ -973,28 +973,6 @@ export function main() { }); })); - - it('should prioritze hostInjector over viewInjector for the same binding', - inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => { - tb.overrideView(MyComp, new viewAnn.View({ - template: ` - - - - - `, - directives: - [DirectiveProvidingInjectableInHostAndView, DirectiveConsumingInjectable] - })); - tb.createView(MyComp, {context: ctx}) - .then((view) => { - var comp = view.rawView.locals.get("consuming"); - expect(comp.injectable).toEqual("host"); - - async.done(); - }); - })); - it("should support viewInjector", inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => { tb.overrideView(DirectiveProvidingInjectableInView, new viewAnn.View({ @@ -1688,23 +1666,15 @@ class GrandParentProvidingEventBus { constructor(bus: EventBus) { this.bus = bus; } } -function createParentBusHost(peb) { +function createParentBus(peb) { return new EventBus(peb, "parent"); } -function createParentBusView(p) { - return p.bus; -} @Component({ selector: 'parent-providing-event-bus', hostInjector: [ new Binding(EventBus, - {toFactory: createParentBusHost, deps: [[EventBus, new visAnn.Unbounded()]]}) - ], - viewInjector: [ - new Binding( - EventBus, - {toFactory: createParentBusView, deps: [[forwardRef(() => ParentProvidingEventBus)]]}) + {toFactory: createParentBus, deps: [[EventBus, new visAnn.Unbounded()]]}) ] }) @View({ @@ -1718,7 +1688,6 @@ class ParentProvidingEventBus { grandParentBus: EventBus; constructor(bus: EventBus, @Unbounded() grandParentBus: EventBus) { - // constructor(bus: EventBus) { this.bus = bus; this.grandParentBus = grandParentBus; }