Skip to content

Commit c51aef9

Browse files
committed
fix(element_injector): changed visibility rules to expose hostInjector of the component to its shadow dom
1 parent bbfb4e1 commit c51aef9

File tree

3 files changed

+47
-51
lines changed

3 files changed

+47
-51
lines changed

modules/angular2/src/core/compiler/element_injector.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -398,41 +398,45 @@ export class ProtoElementInjector {
398398
var bd = [];
399399

400400
ProtoElementInjector._createDirectiveBindingData(bindings, bd, firstBindingIsComponent);
401-
ProtoElementInjector._createHostInjectorBindingData(bindings, bd);
402401
if (firstBindingIsComponent) {
403402
ProtoElementInjector._createViewInjectorBindingData(bindings, bd);
404403
}
405-
404+
ProtoElementInjector._createHostInjectorBindingData(bindings, bd, firstBindingIsComponent);
406405
return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent);
407406
}
408407

409-
private static _createDirectiveBindingData(bindings: List<ResolvedBinding>, bd: List<BindingData>,
408+
private static _createDirectiveBindingData(dirBindings: List<ResolvedBinding>,
409+
bd: List<BindingData>,
410410
firstBindingIsComponent: boolean) {
411-
if (firstBindingIsComponent) {
412-
ListWrapper.push(bd, new BindingData(bindings[0], LIGHT_DOM_AND_SHADOW_DOM));
413-
for (var i = 1; i < bindings.length; ++i) {
414-
ListWrapper.push(bd, new BindingData(bindings[i], LIGHT_DOM));
415-
}
416-
} else {
417-
ListWrapper.forEach(bindings, b => {ListWrapper.push(bd, new BindingData(b, LIGHT_DOM))});
418-
}
411+
ListWrapper.forEach(dirBindings, dirBinding => {
412+
ListWrapper.push(bd, ProtoElementInjector._createBindingData(
413+
firstBindingIsComponent, dirBinding, dirBindings, dirBinding));
414+
});
419415
}
420416

421-
private static _createHostInjectorBindingData(bindings: List<ResolvedBinding>,
422-
bd: List<BindingData>) {
417+
private static _createHostInjectorBindingData(dirBindings: List<ResolvedBinding>,
418+
bd: List<BindingData>,
419+
firstBindingIsComponent: boolean) {
423420
var visitedIds: Map<number, boolean> = MapWrapper.create();
424-
ListWrapper.forEach(bindings, b => {
425-
ListWrapper.forEach(b.resolvedHostInjectables, b => {
421+
ListWrapper.forEach(dirBindings, dirBinding => {
422+
ListWrapper.forEach(dirBinding.resolvedHostInjectables, b => {
426423
if (MapWrapper.contains(visitedIds, b.key.id)) {
427424
throw new BaseException(
428425
`Multiple directives defined the same host injectable: "${stringify(b.key.token)}"`);
429426
}
430427
MapWrapper.set(visitedIds, b.key.id, true);
431-
ListWrapper.push(bd, new BindingData(ProtoElementInjector._createBinding(b), LIGHT_DOM));
428+
ListWrapper.push(bd, ProtoElementInjector._createBindingData(
429+
firstBindingIsComponent, dirBinding, dirBindings,
430+
ProtoElementInjector._createBinding(b)));
432431
});
433432
});
434433
}
435434

435+
private static _createBindingData(firstBindingIsComponent, dirBinding, dirBindings, binding) {
436+
var isComponent = firstBindingIsComponent && dirBindings[0] === dirBinding;
437+
return new BindingData(binding, isComponent ? LIGHT_DOM_AND_SHADOW_DOM : LIGHT_DOM);
438+
}
439+
436440
private static _createViewInjectorBindingData(bindings: List<ResolvedBinding>,
437441
bd: List<BindingData>) {
438442
var db = <DirectiveBinding>bindings[0];

modules/angular2/test/core/compiler/element_injector_spec.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,15 +625,38 @@ export function main() {
625625
expect(inj.get(NeedsService).service).toEqual('service');
626626
});
627627

628-
it("should prioritize hostInjector over viewInjector for the same binding", () => {
628+
it("should prioritize viewInjector over hostInjector for the same binding", () => {
629629
var inj = injector(
630630
ListWrapper.concat([DirectiveBinding.createFromType(NeedsService, new dirAnn.Component({
631631
hostInjector: [bind('service').toValue('hostService')],
632632
viewInjector: [bind('service').toValue('viewService')]})
633633
)], extraBindings), null, true);
634-
expect(inj.get(NeedsService).service).toEqual('hostService');
634+
expect(inj.get(NeedsService).service).toEqual('viewService');
635635
});
636636

637+
it("should instantiate a directive in a view that depends on hostInjector bindings of the component", () => {
638+
var shadowInj = hostShadowInjectors(
639+
ListWrapper.concat([DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component({
640+
hostInjector: [bind('service').toValue('hostService')]})
641+
)], extraBindings),
642+
ListWrapper.concat([NeedsService], extraBindings)
643+
);
644+
expect(shadowInj.get(NeedsService).service).toEqual('hostService');
645+
});
646+
647+
it("should not instantiate a directive in a view that depends on hostInjector bindings of a decorator directive", () => {
648+
expect(() => {
649+
hostShadowInjectors(
650+
ListWrapper.concat([
651+
SimpleDirective,
652+
DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Directive({
653+
hostInjector: [bind('service').toValue('hostService')]})
654+
)], extraBindings),
655+
656+
ListWrapper.concat([NeedsService], extraBindings)
657+
);
658+
}).toThrowError(new RegExp("No provider for service!"));
659+
});
637660

638661
it("should instantiate directives that depend on app services", () => {
639662
var appInjector = Injector.resolveAndCreate(

modules/angular2/test/core/compiler/integration_spec.ts

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -973,28 +973,6 @@ export function main() {
973973
});
974974
}));
975975

976-
977-
it('should prioritze hostInjector over viewInjector for the same binding',
978-
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
979-
tb.overrideView(MyComp, new viewAnn.View({
980-
template: `
981-
<directive-providing-injectable>
982-
<directive-consuming-injectable #consuming>
983-
</directive-consuming-injectable>
984-
</directive-providing-injectable>
985-
`,
986-
directives:
987-
[DirectiveProvidingInjectableInHostAndView, DirectiveConsumingInjectable]
988-
}));
989-
tb.createView(MyComp, {context: ctx})
990-
.then((view) => {
991-
var comp = view.rawView.locals.get("consuming");
992-
expect(comp.injectable).toEqual("host");
993-
994-
async.done();
995-
});
996-
}));
997-
998976
it("should support viewInjector",
999977
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
1000978
tb.overrideView(DirectiveProvidingInjectableInView, new viewAnn.View({
@@ -1688,23 +1666,15 @@ class GrandParentProvidingEventBus {
16881666
constructor(bus: EventBus) { this.bus = bus; }
16891667
}
16901668

1691-
function createParentBusHost(peb) {
1669+
function createParentBus(peb) {
16921670
return new EventBus(peb, "parent");
16931671
}
16941672

1695-
function createParentBusView(p) {
1696-
return p.bus;
1697-
}
16981673
@Component({
16991674
selector: 'parent-providing-event-bus',
17001675
hostInjector: [
17011676
new Binding(EventBus,
1702-
{toFactory: createParentBusHost, deps: [[EventBus, new visAnn.Unbounded()]]})
1703-
],
1704-
viewInjector: [
1705-
new Binding(
1706-
EventBus,
1707-
{toFactory: createParentBusView, deps: [[forwardRef(() => ParentProvidingEventBus)]]})
1677+
{toFactory: createParentBus, deps: [[EventBus, new visAnn.Unbounded()]]})
17081678
]
17091679
})
17101680
@View({
@@ -1718,7 +1688,6 @@ class ParentProvidingEventBus {
17181688
grandParentBus: EventBus;
17191689

17201690
constructor(bus: EventBus, @Unbounded() grandParentBus: EventBus) {
1721-
// constructor(bus: EventBus) {
17221691
this.bus = bus;
17231692
this.grandParentBus = grandParentBus;
17241693
}

0 commit comments

Comments
 (0)