How to use @ViewChild with *ngIf in Angular18+
When working with Angular, you may need to use the *ngIf
directive to conditionally render components. However, if you try to access a view child using @ViewChild
that is hidden by *ngIf
, you may run into issues. In this article, we'll look at how to use @ViewChild
with *ngIf
in Angular.
The problem
When you use *ngIf
to conditionally render a component, Angular will create or destroy the component based on the condition. If you have a view child that depends on this component, you may run into issues trying to access the view child.
Here's an example of how you might define a view child for a component with *ngIf
:
@Component({
selector: 'app-my-component',
template: `
`
})
export class MyComponent implements AfterViewInit {
@ViewChild('myTabs', { static: false }) myTabs!: TabsetComponent;
ngAfterViewInit() {
console.log(this.myTabs);
}
}
In this code, we have a TabsetComponent
inside an *ngIf
directive. We use @ViewChild
to define a view child for the TabsetComponent
. In the ngAfterViewInit
hook, we try to access the view child.
However, if showTabs
is false, the TabsetComponent
won't exist in the DOM, and we'll get a undefined
value for myTabs
.
Read, How To Implement Role-Based Access Control With JWT-Based Authorization In Angular
The solution
To handle the *ngIf
condition and ensure that the view child is properly initialized, we can use a setter method with the @ViewChild
decorator. Here's an updated version of our MyComponent
:
@Component({
selector: 'app-my-component',
template: `
`
})
export class MyComponent implements AfterViewInit {
private _myTabs?: TabsetComponent;
@ViewChild('myTabs', { static: false })
set myTabs(value: TabsetComponent) {
if (value) {
this._myTabs = value;
console.log(this._myTabs);
}
}
ngAfterViewInit() {
console.log(this._myTabs);
}
}
In this code, we define a private property _myTabs
to store the TabsetComponent
instance. We use a setter method with the @ViewChild
decorator to set this property when the TabsetComponent
is initialized.
Inside the setter method, we check whether value
is truthy before assigning it to _myTabs
. This ensures that we don't try to access the view child before it's fully initialized.
In the ngAfterViewInit
hook, we can access the _myTabs
property and use it as needed.
Also read, Optimize Page Load Speed With Lazy Loading Images In Angular 15
Conclusion
Using @ViewChild
with *ngIf
in Angular can be a bit tricky, but by using a setter method, we can handle the condition and ensure that the view child is properly initialized.