fix(core): allow directives to inject the component’s `ChangeDetectorRef`. (#16394)

When a directive lives on the same element as a component
(e.g. `<my-comp myDir>`), the directive was not able to get hold
of the `ChangeDetectorRef` of the component on that element. However,
as directives are supposed to decorate components, this is incorrect.

This commit enables this use case.

Closes #12816
This commit is contained in:
Tobias Bosch 2017-04-27 16:13:47 -07:00 committed by Miško Hevery
parent 900a88b15d
commit 392d584572
2 changed files with 46 additions and 0 deletions

View File

@ -355,6 +355,12 @@ export function resolveDep(
}
const tokenKey = depDef.tokenKey;
if (tokenKey === ChangeDetectorRefTokenKey) {
// directives on the same element as a component should be able to control the change detector
// of that component as well.
allowPrivateServices = !!(elDef && elDef.element !.componentView);
}
if (elDef && (depDef.flags & DepFlags.SkipSelf)) {
allowPrivateServices = false;
elDef = elDef.parent !;

View File

@ -652,6 +652,46 @@ export function main() {
expect(compEl.nativeElement).toHaveText('1');
});
it('should inject ChangeDetectorRef of a same element component into a directive', () => {
TestBed.configureTestingModule(
{declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]});
const cf = createComponentFixture(
'<div componentNeedsChangeDetectorRef directiveNeedsChangeDetectorRef></div>');
cf.detectChanges();
const compEl = cf.debugElement.children[0];
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
const dir = compEl.injector.get(DirectiveNeedsChangeDetectorRef);
comp.counter = 1;
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0');
dir.changeDetectorRef.markForCheck();
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('1');
});
it(`should not inject ChangeDetectorRef of a parent element's component into a directive`, () => {
TestBed
.configureTestingModule({
declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
})
.overrideComponent(
PushComponentNeedsChangeDetectorRef,
{set: {template: '<ng-content></ng-content>{{counter}}'}});
const cf = createComponentFixture(
'<div componentNeedsChangeDetectorRef><div directiveNeedsChangeDetectorRef></div></div>');
cf.detectChanges();
const compEl = cf.debugElement.children[0];
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
const dirEl = compEl.children[0];
const dir = dirEl.injector.get(DirectiveNeedsChangeDetectorRef);
comp.counter = 1;
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0');
dir.changeDetectorRef.markForCheck();
cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0');
});
it('should inject ViewContainerRef', () => {
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]});
const el = createComponent('<div needsViewContainerRef></div>');