🅰️ Angular Q43 / 125

What is ViewChild and ContentChild?

AI-Powered Answer ✓ Answered

In Angular, ViewChild and ContentChild are powerful decorators that allow a component to query and gain programmatic access to elements, directives, or other components within its view or projected content. They are crucial for inter-component communication, direct DOM manipulation, or integrating with third-party libraries.

What are ViewChild and ContentChild?

Both @ViewChild and @ContentChild serve the purpose of querying the DOM within an Angular application. They enable a component to obtain a reference to an element, a component instance, or a directive. The fundamental difference lies in *where* they look for these items: ViewChild looks within the component's *own* template, while ContentChild looks within *projected content*.

ViewChild

The @ViewChild decorator is used to query and get a reference to the first element or the first instance of a directive/component matching the selector from the component's *own view*. This means it looks within the template that is directly associated with the component itself (the content defined in the component's template or templateUrl).

  • Queries elements defined within the component's own template.
  • The queried element is available after the ngAfterViewInit lifecycle hook.
  • Typically used to interact with child components, directives, or native DOM elements that are a direct part of the component's visual structure.
  • Can select by: a template reference variable (e.g., #myElement), a component type, or a directive type.
typescript
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-child-component',
  template: `<p>I am a child component.</p>`
})
export class ChildComponent {
  public message: string = 'Hello from child!';
}

@Component({
  selector: 'app-parent-component',
  template: `
    <h3 #myHeading>Hello ViewChild Example!</h3>
    <app-child-component></app-child-component>
  `
})
export class ParentComponent implements AfterViewInit {
  @ViewChild('myHeading') myHeadingRef!: ElementRef;
  @ViewChild(ChildComponent) childComponentRef!: ChildComponent;

  ngAfterViewInit() {
    // Accessing a native DOM element
    console.log('Heading Text:', this.myHeadingRef.nativeElement.textContent);
    this.myHeadingRef.nativeElement.style.color = 'blue';

    // Accessing a child component instance
    console.log('Child Component Message:', this.childComponentRef.message);
    this.childComponentRef.message = 'Message updated by parent!';
  }
}

ContentChild

The @ContentChild decorator is used to query and get a reference to the first element or the first instance of a directive/component matching the selector from the *content projected* into the component. Content projection (using <ng-content>) allows a parent component to pass content into a child component, and @ContentChild enables the child component to interact with that passed-in content.

  • Queries elements that are passed into the component via content projection (<ng-content>).
  • The queried element is available after the ngAfterContentInit lifecycle hook.
  • Used when a component needs to interact with or manipulate the content it receives from its parent.
  • Can select by: a template reference variable, a component type, or a directive type, similar to ViewChild.
typescript
import { Component, ContentChild, ElementRef, AfterContentInit } from '@angular/core';

@Component({
  selector: 'app-projected-component',
  template: `<p>I am a component projected as content.</p>`
})
export class ProjectedComponent {
  public greet(): string { return 'Hello from projected content!'; }
}

@Component({
  selector: 'app-wrapper-component',
  template: `
    <h2>Wrapper Component</h2>
    <ng-content></ng-content> <!-- This is where content is projected -->
  `
})
export class WrapperComponent implements AfterContentInit {
  @ContentChild('projectedText') projectedTextRef!: ElementRef;
  @ContentChild(ProjectedComponent) projectedComponentRef!: ProjectedComponent;

  ngAfterContentInit() {
    // Accessing a native DOM element from projected content
    if (this.projectedTextRef) {
      console.log('Projected Text:', this.projectedTextRef.nativeElement.textContent);
      this.projectedTextRef.nativeElement.style.fontWeight = 'bold';
    }

    // Accessing a projected component instance
    if (this.projectedComponentRef) {
      console.log('Projected Component Greet:', this.projectedComponentRef.greet());
    }
  }
}

@Component({
  selector: 'app-parent-of-wrapper',
  template: `
    <app-wrapper-component>
      <p #projectedText>This paragraph is content passed to the wrapper.</p>
      <app-projected-component></app-projected-component>
    </app-wrapper-component>
  `
})
export class ParentOfWrapperComponent {}

Key Differences

FeatureViewChildContentChild
PurposeQueries elements from the component's *own* view template.Queries elements from *content projected* into the component (<ng-content>).
Location of SearchWithin the `<template>` or `templateUrl` of the current component.Within the content provided by a parent component and inserted via `<ng-content>`.
Timing of AvailabilityAvailable after the `ngAfterViewInit` lifecycle hook.Available after the `ngAfterContentInit` lifecycle hook.
Use CaseInteracting with internal child components, directives, or DOM elements that the component directly owns and defines.Interacting with external content (components, elements) that a parent provides to the component.

When to use which?

Use @ViewChild when you need to access and manipulate elements, directives, or child components that are defined directly within your component's own template. This is common for internal component interactions or direct DOM manipulation of elements that your component is responsible for. Use @ContentChild when your component is designed to receive content from its parent via content projection (e.g., a modal or tab component), and you need to query or interact with that projected content. This allows for flexible and reusable wrapper components that can customize the behavior of the content they host.