@ViewChild in *ngIf
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;
}
}
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();
}
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
The answers above did not work for me because in my project, the ngIf is on an input element. I needed access to the nativeElement attribute in order to focus on the input when ngIf is true. There seems to be no nativeElement attribute on ViewContainerRef. Here is what I did (following @ViewChild documentation):
<button (click)='showAsset()'>Add Asset</button>
<div *ngIf='showAssetInput'>
<input #assetInput />
</div>
...
private assetInputElRef:ElementRef;
@ViewChild('assetInput') set assetInput(elRef: ElementRef) {
this.assetInputElRef = elRef;
}
...
showAsset() {
this.showAssetInput = true;
setTimeout(() => { this.assetInputElRef.nativeElement.focus(); });
}
I used setTimeout before focusing because the ViewChild takes a sec to be assigned. Otherwise it would be undefined.