ContentChild
is an essential Angular decorator that allows developers to access child components, directives, or elements that are projected into a component using Angular’s Content Projection mechanism (ng-content
). This decorator is useful for managing dynamic components, templates, and advanced component interaction.
In this article, we’ll cover what ContentChild
is, its syntax, how it works, and practical examples of using it in Angular.
What is ContentChild
?
ContentChild
is an Angular decorator that marks a class property as a query for a content-projected child element, directive, or component. It is often used when you want to interact with a single child that is projected into a parent component using <ng-content>
.
When to Use ContentChild
Use ContentChild
when:
- You need to access an element, directive, or component that is projected into the component’s view.
- You want to interact with or modify a child element directly from the parent component.
- You need to perform operations like event handling or property updates on the projected content.
Basic Syntax of ContentChild
The syntax for using ContentChild
is as follows:
typescriptCopy code@ContentChild(selector, {static: boolean})
selector
: Specifies the component, directive, or template reference variable to be queried.static
: A boolean value that indicates whether to resolve the query before change detection runs. Generally, set tofalse
for dynamic content.
How ContentChild
Works
The ContentChild
decorator queries for the first occurrence of the specified content-projected element and assigns it to a property in the parent component. It provides a reference to the child element, allowing the parent component to interact with it directly.
The lifecycle hook ngAfterContentInit()
is often used alongside ContentChild
because it runs after the content projection has been initialized.
Example 1: Accessing a Child Component with ContentChild
Let’s look at a basic example where we use ContentChild
to access a child component projected into a parent component.
Step 1: Create a Child Component
typescriptCopy code// child.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>I am the child component!</p>`,
})
export class ChildComponent {
public message: string = 'Hello from Child Component!';
public sayHello(): string {
return this.message;
}
}
Step 2: Create a Parent Component with ContentChild
In the parent component, we’ll use the <ng-content>
tag to allow content projection and use ContentChild
to access the child component.
typescriptCopy code// parent.component.ts
import { Component, AfterContentInit, ContentChild } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="callChildMethod()">Call Child Method</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChild(ChildComponent) child!: ChildComponent;
ngAfterContentInit(): void {
console.log('Child Component Message:', this.child.message);
}
callChildMethod(): void {
alert(this.child.sayHello());
}
}
Step 3: Use Parent and Child Components Together
In the app’s main template, we project the child component into the parent component.
htmlCopy code<!-- app.component.html -->
<app-parent>
<app-child></app-child>
</app-parent>
In this example:
- The
app-child
component is projected into theapp-parent
component using content projection. - The parent component uses
ContentChild
to access the child component and calls its method when the button is clicked.
Example 2: Accessing a Template Reference Variable
You can also use ContentChild
to access a template reference variable projected into a parent component.
Step 1: Define the Template Reference in Child Component
htmlCopy code<!-- child.component.html -->
<p #childTemplate>Hello from Template Reference!</p>
Step 2: Use ContentChild
in Parent Component
typescriptCopy code// parent.component.ts
import { Component, AfterContentInit, ContentChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="changeText()">Change Text</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChild('childTemplate', { static: false }) childTemplate!: ElementRef;
ngAfterContentInit(): void {
console.log('Initial Text:', this.childTemplate.nativeElement.textContent);
}
changeText(): void {
this.childTemplate.nativeElement.textContent = 'Text changed by Parent!';
}
}
Here:
- The
@ContentChild('childTemplate')
decorator is used to access the template reference#childTemplate
. - The parent component modifies the text content of the projected template reference.
Example 3: Accessing a Directive with ContentChild
You can also query directives projected into a component using ContentChild
.
Step 1: Create a Directive
typescriptCopy code// highlight.directive.ts
import { Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector: '[appHighlight]',
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
}
changeColor(color: string): void {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
Step 2: Use the Directive with ContentChild
typescriptCopy code// parent.component.ts
import { Component, AfterContentInit, ContentChild } from '@angular/core';
import { HighlightDirective } from './highlight.directive';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="changeColor()">Change Color</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChild(HighlightDirective) highlightDirective!: HighlightDirective;
ngAfterContentInit(): void {
console.log('Highlight Directive Found:', !!this.highlightDirective);
}
changeColor(): void {
this.highlightDirective.changeColor('lightblue');
}
}
Here, the parent component queries for the HighlightDirective
applied to any projected content, allowing it to change the color dynamically.
Key Points to Remember about ContentChild
- Only Works with Projected Content:
ContentChild
can only access elements, components, or directives that are projected using<ng-content>
. - Lifecycle Hook: Use
ngAfterContentInit()
to safely access the queried element since the projected content becomes available after initialization. - Static vs. Dynamic: Set
{ static: false }
for dynamically rendered content and{ static: true }
if you need access during the initialization phase. - First Matched Element:
ContentChild
retrieves the first matched element. For multiple elements, useContentChildren
.
ContentChild
is a powerful tool for interacting with projected content in Angular. It allows parent components to gain access to child elements, components, and directives that are dynamically projected into their template. By using ContentChild
effectively, you can create highly dynamic and interactive components in Angular.
Happy coding! 🚀