Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ViewChild in *ngIf

Question

What is the most elegant way to get @ViewChild after corresponding element in template was shown?

Below is an example. Also Plunker available.

Component.template.html:

<div id="layout" *ngIf="display">   <div #contentPlaceholder></div> </div> 

Component.component.ts:

export class AppComponent {      display = false;     @ViewChild('contentPlaceholder', { read: ViewContainerRef }) viewContainerRef;      show() {         this.display = true;         console.log(this.viewContainerRef); // undefined         setTimeout(() => {             console.log(this.viewContainerRef); // OK         }, 1);     } } 

I have a component with its contents hidden by default. When someone calls show() method it becomes visible. However, before Angular 2 change detection completes, I can not reference to viewContainerRef. I usually wrap all required actions into setTimeout(()=>{},1) as shown above. Is there a more correct way?

I know there is an option with ngAfterViewChecked, but it causes too much useless calls.

ANSWER (Plunker)

like image 346
sinedsem Avatar asked Sep 07 '16 10:09

sinedsem


2 Answers

Use a setter for the ViewChild:

 private contentPlaceholder: ElementRef;   @ViewChild('contentPlaceholder') set content(content: ElementRef) {     if(content) { // initially setter gets called with undefined         this.contentPlaceholder = content;     }  } 

The setter is called with an element reference once *ngIf becomes true.

Note, for Angular 8 you have to make sure to set { static: false }, which is a default setting in other Angular versions:

 @ViewChild('contentPlaceholder', { static: false }) 

Note: if contentPlaceholder is a component you can change ElementRef to your component Class:

  private contentPlaceholder: MyCustomComponent;    @ViewChild('contentPlaceholder') set content(content: MyCustomComponent) {      if(content) { // initially setter gets called with undefined           this.contentPlaceholder = content;      }   } 
like image 115
parliament Avatar answered Oct 08 '22 04:10

parliament


An alternative to overcome this is running the change detector manually.

You first inject the ChangeDetectorRef:

constructor(private changeDetector : ChangeDetectorRef) {} 

Then you call it after updating the variable that controls the *ngIf

show() {         this.display = true;         this.changeDetector.detectChanges();     } 
like image 20
Jefferson Lima Avatar answered Oct 08 '22 04:10

Jefferson Lima