ContentChildren
is a powerful Angular decorator that allows developers to query and access multiple elements, directives, or components that are projected into a parent component using Angular’s content projection mechanism (ng-content
). Unlike ContentChild
, which fetches only the first matching element, ContentChildren
retrieves all matching elements and provides them as a QueryList
.
In this article, we’ll explore the workings of ContentChildren
, its syntax, use cases, and some practical examples.
What is ContentChildren
?
ContentChildren
is an Angular decorator that queries for multiple projected elements, directives, or components within a parent component’s template. It is commonly used to handle projected content when you need to interact with a collection of child elements.
When to Use ContentChildren
- When you need to access multiple projected elements or components: Use
ContentChildren
when you want to work with more than one content-projected child. - When you need to perform operations on a list of elements: It’s helpful for iterating, modifying, or observing changes on multiple child components or directives.
- When building reusable components that manage dynamic content: It is ideal for building components that manage a dynamic number of child components.
Basic Syntax of ContentChildren
The syntax for using ContentChildren
is as follows:
typescriptCopy code@ContentChildren(selector, { read: value, descendants: boolean })
selector
: The component, directive, or template reference variable to be queried.read
(optional): Specifies what to read, such asElementRef
,TemplateRef
, or a specific directive instance.descendants
: A boolean that determines whether to include nested children in the query.
How ContentChildren
Works
ContentChildren
returns a QueryList
, which is a specialized Angular object that represents a dynamic list of queried elements. This list is updated automatically whenever changes are detected in the projected content. You can use the changes
observable of QueryList
to monitor updates to the list.
The decorator is often used with the lifecycle hook ngAfterContentInit()
to ensure the projected content is initialized before accessing it.
Example 1: Accessing Multiple Projected Components with ContentChildren
Step 1: Create Child Components
First, let’s create a simple child component.
typescriptCopy code// child.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>Child Component</p>`,
})
export class ChildComponent {}
Step 2: Use ContentChildren
in the Parent Component
In the parent component, we’ll project multiple instances of the child component and use ContentChildren
to query them.
typescriptCopy code// parent.component.ts
import { Component, ContentChildren, AfterContentInit, QueryList } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="showChildCount()">Show Child Count</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChildren(ChildComponent) children!: QueryList<ChildComponent>;
ngAfterContentInit(): void {
console.log('Number of Child Components:', this.children.length);
}
showChildCount(): void {
alert(`Number of Child Components: ${this.children.length}`);
}
}
Step 3: Project Multiple Child Components
In the main app template, project multiple instances of the child component into the parent component.
htmlCopy code<!-- app.component.html -->
<app-parent>
<app-child></app-child>
<app-child></app-child>
<app-child></app-child>
</app-parent>
In this example:
- We project three
app-child
components into theapp-parent
component. - The
ContentChildren
decorator retrieves all the projected children and logs the number of instances.
Example 2: Using ContentChildren
with Template Reference Variables
You can also use ContentChildren
to query elements based on template reference variables.
Step 1: Define Template References in the Projected Content
htmlCopy code<!-- projected-content.component.html -->
<p #childRef>Child 1</p>
<p #childRef>Child 2</p>
<p #childRef>Child 3</p>
Step 2: Use ContentChildren
in the Parent Component
typescriptCopy code// parent.component.ts
import { Component, ContentChildren, AfterContentInit, QueryList, ElementRef } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="highlightChildren()">Highlight Children</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChildren('childRef', { read: ElementRef }) children!: QueryList<ElementRef>;
ngAfterContentInit(): void {
console.log('Number of Projected Elements:', this.children.length);
}
highlightChildren(): void {
this.children.forEach((child) => {
child.nativeElement.style.backgroundColor = 'yellow';
});
}
}
Here:
- The
ContentChildren
decorator is used to access elements with the template reference#childRef
. - The parent component changes the background color of each projected element when the button is clicked.
Example 3: Using ContentChildren
with Directives
You can also use ContentChildren
to query directives applied to projected content.
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', 'lightblue');
}
}
Step 2: Use ContentChildren
in the Parent Component
typescriptCopy code// parent.component.ts
import { Component, ContentChildren, AfterContentInit, QueryList } from '@angular/core';
import { HighlightDirective } from './highlight.directive';
@Component({
selector: 'app-parent',
template: `
<ng-content></ng-content>
<button (click)="changeHighlight()">Change Highlight Color</button>
`,
})
export class ParentComponent implements AfterContentInit {
@ContentChildren(HighlightDirective) highlights!: QueryList<HighlightDirective>;
ngAfterContentInit(): void {
console.log('Number of Highlighted Elements:', this.highlights.length);
}
changeHighlight(): void {
this.highlights.forEach((highlight) => {
highlight.changeColor('pink');
});
}
}
In this example:
- The
ContentChildren
decorator retrieves all instances of theHighlightDirective
applied to the projected elements. - The parent component changes the background color of each element managed by the directive.
Key Features of ContentChildren
- Returns a
QueryList
:ContentChildren
returns aQueryList
of matching elements, directives, or components. - Dynamic Updates: The
QueryList
is updated automatically when the projected content changes. - Works with Directives, Components, and Template References: It can query various types of projected content.
- Supports Deep Queries: By setting the
descendants
option totrue
, you can include nested elements in the query.
Common Use Cases for ContentChildren
- Managing lists of dynamic elements: Access multiple projected components or elements that require similar behavior.
- Building UI frameworks: Ideal for creating complex, reusable UI components that manage child components.
- Iterating over projected content: When working with a collection of dynamically added components,
ContentChildren
simplifies interaction and management.
Conclusion
ContentChildren
is a versatile and powerful Angular feature for working with multiple projected elements, components, and directives. By understanding how to use ContentChildren
, you can build more dynamic, flexible, and interactive Angular applications. This decorator is especially useful for creating advanced UI components and handling complex content projection scenarios.
Happy coding! 🚀