简体   繁体   中英

Angular 8 - @ViewChild returns undefined on parent component. (no nested ngIf and called in ngAfterViewInit)

Hope someone can enlighten me.

Problem

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;

Expected

To have directive reference in childRef instance variable when the event happens.

Actual

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: :/

Reproduction

Situation

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>

Code

//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)
  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM