30

I've a problem using @ViewChild with a component showed through ngIf. I found various solutions but no one usefull for me. This is my main component, consisting of various step (I showed only 2 in code for brevity) with a button for forward navigation and a button to reset the component returning on first step. First step is showed on page opening:

...
<div class="my-container">
    <first-child *ngIf="showFirtChild"></first-child>
    <second-child *ngIf="showSecondChild"></second-child>
</div>
<button (click)="goToNextStep()"></button>
<button (click)="reset()"></button>
...
export class MainComponent implements OnInit {
    @ViewChild(FirstChild) private firstChildComp: MyFirstChildComponent;
    showFirtChild: boolean = true;

    ngOnInit() {
        //here firstChildComp is defined
    }

    //code for navigate through steps
    reset() {
        this.showFirtChild= true;
        this.firstChildComp.fillTable(); //fillTable is a function defined in MyFirstChildComponent
    }
...
}

During steps navigation the reference to firstChildComp is lost and when reset() is called, childComp results undefined. I know the cause is ngIf, so I tryed to use ngAfterViewInit:

ngAfterViewInit() {
    this.fcomp = this.firstChildComp;
}

reset() {
        this.showFirtChild= true;
        this.fcomp .fillTable();
}

but it doesn't resolve my problem. Any suggestion?

porgo
  • 1,729
  • 2
  • 17
  • 26
bigskull
  • 541
  • 2
  • 18
  • 28

4 Answers4

28

As Angular's Doc says:

"True to resolve query results before change detection runs. If any query results are inside a nested view (such as *ngIf), the query is resolved after change detection runs."

So, passing the param { static: false } to @ViewChild resolve the problem, as it is accessed on ngAfterViewInit, instead on { static: true } is accessed before change detection runs so on ngOnInit.

19

ngIf will remove you component from the DOM. So it becomes undefined. If you use [hidden]="!showFirstChild" instead, it will be only hidden, and will be available in the component.

Here is a stackblitz where you can check this.

16

Try running change detection in between to ensure the DOM template is reading the DOM after the change in reset.

In template:

<first-child #firstChild *ngIf="showFirtChild"></first-child>

In controller:

import { ChangeDetectorRef } from '@angular/core';

export class exampleClass implements 
{

  @ViewChild('firstChild') public firstChildComp: MyFirstChildComponent;
  public fcomp: any;
  public showFirtChild: boolean;

  constructor(private ref: ChangeDetectorRef,
            //your services) {}

  public ngAfterViewInit() 
  {
      this.showFirtChild = true;
      this.ref.detectChanges();

      this.fcomp = this.firstChildComp;
  }

  public reset(): void 
  {
      this.fcomp.fillTable();
  }
}

ChangeDetectorRef Documentation for further reading.

Marco
  • 1,073
  • 9
  • 22
devDan
  • 5,969
  • 3
  • 21
  • 40
  • sorry check edit, should be good. If that does not work please explain whats not happening or any errors. – devDan Apr 10 '19 at 12:16
  • With your edit fcomp in reset() is correctly defined but nothing changes. This is very strange, it's like the fillTable() is executed, infact no errors appear, but it does nothing... Using debugger I can see that fcomp is correct and the instruction is executed but the table is not filled... – bigskull Apr 10 '19 at 12:46
  • Okay so you have sorted the viewChild problems? Not sure I can help with populating the table correctly. Put a console.log(); in fillTable(); and if you can see it then there is a problem with the function. – devDan Apr 10 '19 at 12:48
  • It's not problem of the table, because each other method of MyFirstChildComponent is executed but it actually does nothing. – bigskull Apr 10 '19 at 12:50
  • So if in MyFirstChildComponent you ran this.fillTable() it would work ? – devDan Apr 10 '19 at 12:54
  • Sorry, I try to explain: on page opening I call reset() and it works correctly. After passing to other step and back to first recalling reset() it doesn't work. I repeat it's like the method is executed but nothing changes (this happens for each other method of child component). I note this: on second reset(), ngAfterViewInit() isn't executed, so I thing fcomp is defined but, in fact, it doesn't work properly. – bigskull Apr 10 '19 at 13:09
  • So has this fixed the issue with the viewchild being undefined? – devDan Apr 11 '19 at 11:04
  • Yes, but unfortunatly doesn't solve my problem totally. Thanks – bigskull Apr 11 '19 at 13:27
  • this is the only thing that worked why isn't this answer accepted and +322342? – vzR May 21 '19 at 14:05
  • haha I think the poster was having a unrelated problem as well, glad to help :-) – devDan May 21 '19 at 14:08
  • This helped me a lot and is very simple to do. I don't understand though why Angular doesn't run change detection after the ngif is toggled... – jiroch Nov 17 '19 at 20:12
  • Works perfectly on Angular < 8 version, thank you a lot – NeitoFR May 04 '20 at 20:33
1

If you are still looking for an answer, you can also try setting the static flag value on true. That will make the child component viewContainerRef loads depending on the ngIf value.

Nappy
  • 3,016
  • 27
  • 39