Search code examples
angularviewchild

Call a method in the nested component


I have two components (1-app-student-list 2-app-student-detail).

I want to use student-detail in the student-list like the following :

app-student-detail.html

<p>Student Detail Component is here ....</p>

app-student-detail.ts

export class StudentDetailComponent {
  showDetail() {
    alert("We are in student-detail...");
  }
}

app-student-list.html

<p>Student List Component is here ....</p>
<app-student-detail></app-student-detail>

app-student-list.ts

export class StudentListComponent implements OnInit {

  @ViewChild(StudentDetailComponent, { static: true }) studentDetail: StudentDetailComponent;
  constructor() { }

  ngOnInit() {
  }

  showDetail() {
    this.studentDetail.showDetail();
  }

}

In the showDetail method I want to call a method of StudentDetailComponent named showDetail

And finally, I want to use student-list in the AppComponent

app.component.ts

export class AppComponent {
  public isShow = false;

  @ViewChild(StudentListComponent, { static: true }) studentList: StudentListComponent;
  title = 'AngualrViewChild';

  showDetail() {
    this.isShow = true;
    this.studentList.showDetail();
  }

}

app.component.html

<p>App Component is here ....</p>
<app-student-list *ngIf="this.isShow"></app-student-list>

<hr />
<button type="button" (click)="this.showDetail()">
    Show Detail
</button>

When I call the showDetail method of StudentListComponent I get the following Error :

AppComponent.html:6 ERROR TypeError: Cannot read property 'showDetail' of undefined

Note: When I remove ngIf above it will work perfectly

Stackblitz is here


Solution

  • When your student list is not shown (your *ngIf evaluates to false), then your StudentList is also not rendered/available anywhere.

    Therefore, your ViewChild can't resolve to anything and the call "this.studentList.showDetail();" won't work. Yes, you changed your boolean value to true, but the changeDetection may not have enough time to run and actually render your StudentList.

    In your App.Component, you should also reconsider your :

    { static: true }
    

    Your viewchild, currently, is far from static as it depends on the *ngIf to resolve. Setting it to "static: true" will prevent your ViewChild from updating when your StudentList actually becomes available.

    More info about this property.

    You have two options here.

    1. (dirty workaround) Switch your boolean value to true, allow your *ngIf to perform the correct changes (display your StudentList) and then you call your showDetails method like this :

    enter image description here

    1. (cleaner) If you want a function to be called as soon as your StudentList is available, you could implement AfterViewInit() in your StudentList.component and call your function.

    For example :

    import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
    

    AfterViewInit implementation

    Both should give you the result you are expecting, but before calling child component functions from the parent component, think about WHY you want to do that.

    Do you actually want the parent to trigger an action on the children, or do you want the children to do something once he has reached a certain lifecycle ? Most of the time, the logic can be implemented in the children and your parent component can only care about rendering the child or hide it.