Angular: Using @ContentChildren To Get Children Inside Another Component


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:

  1. Basic knowledge of Angular.
  2. Angular CLI installed on your system.
  3. 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.

Demo

Next Post Previous Post
No Comment
Add Comment
comment url