In Angular, you often work with parent-child component relationships, where a parent component contains child components. To interact with and manage these child components, Angular provides decorators like @ContentChildren
. In this blog post, we’ll explore how to use @ContentChildren
to efficiently manage child components within a parent component.
Prerequisites
Before we begin, ensure that you have the following prerequisites:
- Basic knowledge of Angular.
- Angular CLI installed on your system.
- A code editor of your choice (e.g., Visual Studio Code).
What is @ContentChildren?
@ContentChildren
is an Angular decorator used to query for child components or elements within the content projection area of a parent component. It allows you to collect references to these child components or elements and perform actions on them. This is particularly useful when you need to interact with and manage child components dynamically.
Creating a Tabbed Interface Example
Let’s create a simple example to demonstrate how to use @ContentChildren
. We’ll build a tabbed interface where the parent component, TabGroupComponent
, manages multiple tab components, TabComponent
, and displays the active tab’s content.
Step 1: Generating Components
First, create the components using Angular CLI:
ng generate component tab-group
ng generate component tab
Step 2: Tab Component Implementation
In the tab.component.ts
file, define the TabComponent
as follows:
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-tab',
template: `
<div [hidden]="!active">
<ng-content></ng-content>
</div>
`,
})
export class TabComponent {
@Input() label: string;
@Input() active = false;
}
Here, we have a TabComponent
that accepts inputs for the tab label and its active state. It uses ng-content
to project content into the tab.
Step 3: Tab Group Component Implementation
Next, in the tab-group.component.ts
file, define the TabGroupComponent
:
import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { TabComponent } from './tab.component';
@Component({
selector: 'app-tab-group',
template: `
<div class="tab-group">
<div class="tab-labels">
<ng-container *ngFor="let tab of tabs">
<div
class="tab-label"
[class.active]="tab.active"
(click)="activateTab(tab)"
>
{{ tab.label }}
</div>
</ng-container>
</div>
<ng-content></ng-content>
</div>
`,
styleUrls: ['./tab-group.component.css'],
})
export class TabGroupComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
ngAfterContentInit() {
// Initialize the first tab as active.
if (this.tabs.length > 0) {
this.activateTab(this.tabs.first);
}
}
activateTab(selectedTab: TabComponent) {
// Deactivate all tabs.
this.tabs.forEach((tab) => (tab.active = false));
// Activate the selected tab.
selectedTab.active = true;
}
}
In the TabGroupComponent
, we use @ContentChildren(TabComponent)
to query for all child components of type TabComponent
. During the ngAfterContentInit
lifecycle hook, we initialize the first tab as active. When a tab label is clicked, the activateTab
method is called to deactivate all tabs and activate the selected tab.
Step 4: Styling the Tabs
Create a CSS file, tab-group.component.css
, to style the tabs:
/* tab-group.component.css */
.tab-group {
border: 1px solid #ccc;
border-radius: 4px;
margin: 16px;
}
.tab-labels {
display: flex;
justify-content: space-between;
background-color: #f0f0f0;
border-bottom: 1px solid #ccc;
}
.tab-label {
padding: 8px 16px;
cursor: pointer;
user-select: none;
}
.tab-label.active {
background-color: #fff;
border-bottom: 1px solid #fff;
}
Step 5: Using the Tab Group Component
Finally, in your application’s HTML, you can use the TabGroupComponent
to create a tabbed interface:
<app-tab-group>
<app-tab label="Tab 1">
<p>Content for Tab 1 goes here.</p>
</app-tab>
<app-tab label="Tab 2" [active]="true">
<p>Content for Tab 2 goes here.</p>
</app-tab>
<app-tab label="Tab 3">
<p>Content for Tab 3 goes here.</p>
</app-tab>
</app-tab-group>
Here, we have three TabComponent
elements nested within the TabGroupComponent
. The label
input defines the tab label, and the active
input specifies the active tab.
Conclusion
In this blog post, we explored how to use @ContentChildren
in Angular to efficiently manage child components within a parent component. We created a tabbed interface example where the parent component, TabGroupComponent
, dynamically manages multiple TabComponent
instances. This approach enables you to create flexible and reusable components that can be used in various scenarios where dynamic child component management is required.