@ViewChild in *ngIf
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();
}
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;
}
}
Angular 8+
You should add { static: false }
as a second option for @ViewChild
. This causes the query results to be resolved after change detection runs, allowing your @ViewChild
to be updated after the value changes.
Example:
export class AppComponent {
@ViewChild('contentPlaceholder', { static: false }) contentPlaceholder: ElementRef;
display = false;
constructor(private changeDetectorRef: ChangeDetectorRef) {
}
show() {
this.display = true;
// Required to access this.contentPlaceholder below,
// otherwise contentPlaceholder will be undefined
this.changeDetectorRef.detectChanges();
console.log(this.contentPlaceholder);
}
}
Stackblitz example: https://stackblitz.com/edit/angular-d8ezsn