What is ViewChild and ContentChild?
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
ngAfterViewInitlifecycle 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.
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
ngAfterContentInitlifecycle 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.
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
| Feature | ViewChild | ContentChild |
|---|---|---|
| Purpose | Queries elements from the component's *own* view template. | Queries elements from *content projected* into the component (<ng-content>). |
| Location of Search | Within the `<template>` or `templateUrl` of the current component. | Within the content provided by a parent component and inserted via `<ng-content>`. |
| Timing of Availability | Available after the `ngAfterViewInit` lifecycle hook. | Available after the `ngAfterContentInit` lifecycle hook. |
| Use Case | Interacting 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.