@ViewChild - initializer error on Angular 13
I am creating app in Angular 13. I want to call the method show()
of ChildComponent
from ParentComponent
, using @ViewChild
, but I get errors. The older questions and answers are not working in this case.
Parent:
<app-child #child></app-child>
@ViewChild('child') child: ChildComponent;
showChild() {
this.child.show();
}
Child:
show(){
console.log('show');
}
Error:
Property 'child' has no initializer and is not definitely assigned in the constructor.
Solution 1:
Parent:
@ViewChild('child') child!: ChildComponent;
Error:
TypeError: Cannot read properties of undefined (reading 'show')
Solution 2:
Parent:
@ViewChild('child') child: ChildComponent = new ChildComponent;
Without errors Works fine but I have doubts if this is correct?
you can initialize like that. Ii will help you to resolvee your error.
@ViewChild('child') child: ChildComponent = {} as ElementRef;
or
@ViewChild('child') child: ChildComponent = {} as ChildComponent;
Solution for your doubt-
Parent-
<app-child></app-child>
@ViewChild('child') child: ChildComponent;
ngAfterViewInit() {
// When accessing with ViewChild(), use this lifecycle hook
// to call methods or for anything related to that component
this.child.show();
}
Child-
show(){
console.log('HELLO WORLD');
}
Extra information on accessing the child component-
There are 3 ways of querying over child component, children of component or over Html DOM Elements by angular and the earliest possible moment when you can get objects of queried DOM or component is in ngAfterViewInit
lifecycle hook.
1.) Querying based on the name of the Component
app.component.ts
@ViewChild('cardRef', {read: ElementRef}) card1: ElementRef; //by this you can achieve querying over HTML DOM objects
@ViewChild('container') containerDiv: ElementRef;
ngAfterViewInit() {
console.log("cardRef = ", this.card1);
console.log("container = ", this.containerDiv);
}
app.component.html
<div class="product" #container>
<product-card #cardRef></product-card>
</div>
2.) Querying based on the reference. This is useful when you have multiple cards coming with different sets of data and in case you want to manipulate any of them.
app.component.ts
@ViewChild('cardRef1') card1: ProductCardComponent;
@ViewChild('cardRef2') card2: ProductCardComponent;
ngAfterViewInit() {
console.log("cardRef1 = ", this.card1);
console.log("cardRef2 = ", this.card2);
}
app.component.html
<div class="product">
<product-card #cardRef1 [course]="course[0]"></product-card>
<product-card #cardRef2 [course]="course[1]"></product-card>
</div>
3.) When you have query over a list of collection, you can use @ViewChildren() decorator.
app.component.ts
@ViewChildren(ProductCardComponent) cards: QueryList<ProductCardComponent>; //QueryList will give a lot methods embedded in it (e.g. first, last, forEach, etc)
ngAfterViewInit() {
console.log(this.cards.first); //It will give the object for the first card
}
app.component.html
<div class="product" #container>
<product-card *ngFor="let product of products"></product-card>
</div>
I hope this clears your doubt.