Hope someone can enlighten me.
I need to get a reference to a directive placed inside an inner component. I'm using @ViewChild targeting Directive class, with {static:true}since it doesnt have to wait for state changes and use it later on lifecicle when the user clicks a button.
@ViewChild(DirectiveClass, {static:true}) childRef : DirectiveClass;
To have directive reference in childRef instance variable when the event happens.
childRef is undefined
I did research for similar problems and all seemed to be because ref was inside a *ngIf and should be {static: false}; or because the ref was intended to be used before it was fetched(before ngAfterViewInit hook). This is not the case, this case is fair simplier and yet cant get whats wrong! :/
so, I got two components and a directive. Lets call them ParentComponent and SonComponent. Directive is applied in son component, so lets call it SonDirective.
Basically this is the structure.
<app-parent>
<app-son> </app-son> //<- Directive inside
</app-parent>
//parent.component.ts
@Component({
selector: 'app-parent',
template: `
<div>
<h2> parent </h2>
<app-son></app-son>
</div>
`,
})
export class AppParentComponent implements AfterViewInit{
@ViewChild(AppSonDirective,{static: true}) childRef : AppSonDirective;
constructor() {}
ngAfterViewInit() {
console.log("childRef:",this.childRef)
}
}
// son.component.ts
@Component({
selector: 'app-son',
template: `
<div appSonDirective>
<p> son <p>
</div>
`,
})
export class AppSonComponent {
constructor() {}
}
//son.directive.ts
@Directive({
selector: '[appSonDirective]'
})
export class AppSonDirective {
constructor(){}
}
Note: if i move the view child ref to the son component it can be accessed. The issue seems to be at parent component (?)
Anyway... here is the reproducion code(it has some logs to know whats going on)
Any thoughts will be helpfull.
Thanks in advance! :)
Problem is that @ViewChild
only works around the component DOM but don't have access to the DOM of its children components, that would break encapsulation between components. In this case appSonDirective
is declared in AppSonComponent
DOM but because you're trying to access it from AppParentComponent
it returns undefined
because AppParentComponent
can't access AppSonComponent
DOM. It could work if you had something like this:
<app-parent>
<app-son appSonDirective></app-son>
</app-parent>
One solution is to expose the directive as a property of you child component. Something like:
@Component({
selector: 'app-son',
template: `
<div appSonDirective>
<p> son <p>
</div>
`,
})
export class AppSonComponent {
@ViewChild(AppSonDirective,{static: true}) childRef : AppSonDirective;
constructor() {}
}
and then in AppParentComponent
@Component({
selector: 'app-parent',
template: `
<div>
<h2> parent </h2>
<app-son></app-son>
</div>
`,
})
export class AppParentComponent implements AfterViewInit{
@ViewChild(AppSonComponent,{static: true}) son : AppSonComponent;
constructor() {}
ngAfterViewInit() {
console.log("childRef:",this.son.childRef)
}
}