Accessing Child Component Instances using ContentChild and ContentChildren
In Angular, @ContentChild
and @ContentChildren
decorators are used to access child components or directives that are projected into the component using the <ng-content>
element. These decorators work with the content of the component, which is the content projected by the parent component.
Here’s a brief explanation of how to use @ContentChild
and @ContentChildren
:
@ContentChild
:
- Similarly like
@ViewChild
,@ContentChild
is used to get the first instance of a child component or directive that matches the specified selector within the projected content. - Typically used when there is a single occurrence of the child component or directive.
- Should be used in conjunction with the
ngAfterContentInit
lifecycle hook.
@ContentChildren
:
- Used to get a
QueryList
containing all instances of child components or directives that match the specified selector within the projected content. - Suitable when there are multiple occurrences of the child component or directive.
- Should be used in conjunction with the
ngAfterContentInit
lifecycle hook.
ngAfterContentInit
:
- A lifecycle hook called after the component’s content has been projected and initialized.
- Provides a safe place to interact with child components or directives within the content.
- Use it when you need to access content children using
@ContentChild
or@ContentChildren
.
Here is simple code example:
Parent Component:
<div class="courses" *ngIf="course">
<course-card (courseSelected)="onCourseSelected($event)" [course]="course">
<img select="[img]"
src="{{ course.iconUrl }}"
#courseImage
/>
<div class="course-description" select="[description]">
{{ course?.longDescription }}
</div>
<h5>Remaining content</h5>
</course-card>
</div>
Here, in the parent component, #courseImage
is projected in child using <ng-content>
.
Child Component:
<div class="course-card" [ngClass]="cardClasses()" *ngIf="showCard">
<div class="course-title" *ngIf="course?.description">
{{ course?.description }}
</div>
<ng-content select="img"></ng-content>
<ng-content select=".course-description"></ng-content>
<ng-content></ng-content>
<button (click)="onCourseViewed(course)">View course</button>
</div>
Now, in the child component’s .ts file, if you try to get the reference of #courseImage
using @ViewChild
, it will return undefined.
@ViewChild('courseImage')
courseImage;
ngAfterViewInit() {
console.log("Course Image: ", this.courseImage);
}
Now, if you try to get this using @ContentChild
, you will get the desired element. Here is the changes which you need to made in the code.
@ContentChild('courseImage')
courseImage;
ngAfterContentInit() {
console.log("Course Image: ", this.courseImage);
}
Note: You need to use ngAfterContentInit
lifecycle hook instead of ngAfterViewInit
. The ngAfterContentInit
lifecycle hook is guaranteed to be called after the content has been projected and initialized.
Summary, Keep in mind that if you’re trying to access the content projected through ng-content
in a parent component, you won't be able to do so directly using @ViewChild
in the child component. Instead, you might need to pass data or references through inputs and outputs to achieve the desired communication between components or you need to use @ContentChild
and @ContentChildren
.