Explain the Angular component lifecycle hooks.
Angular components and directives have a well-defined lifecycle, managed by Angular itself. Lifecycle hooks allow you to tap into key moments during a component's or directive's existence, from its creation to its destruction, enabling you to perform actions at specific times.
Understanding Lifecycle Hooks
Every Angular component has a lifecycle. Angular provides lifecycle hook interfaces that allow developers to hook into these lifecycle events, executing custom logic at precise moments. These hooks are methods prefixed with ng that are called by Angular automatically.
Primary Lifecycle Hooks
ngOnChanges
Responds when Angular sets or resets data-bound input properties. The method receives a SimpleChanges object of current and previous property values. This hook is called before ngOnInit and whenever one or more data-bound input properties change.
import { Component, OnChanges, Input, SimpleChanges } from '@angular/core';
@Component({ selector: 'app-child', template: '<p>Value: {{ data }}</p>' })
export class ChildComponent implements OnChanges {
@Input() data: string;
ngOnChanges(changes: SimpleChanges): void {
for (let propName in changes) {
let change = changes[propName];
let current = JSON.stringify(change.currentValue);
let previous = JSON.stringify(change.previousValue);
console.log(`${propName}: currentValue = ${current}, previousValue = ${previous}`);
}
}
}
ngOnInit
Initializes the component or directive after Angular first displays the data-bound properties and sets the component's input properties. This is a good place to fetch data from a server or perform other initialization tasks that don't depend on input changes.
import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-hello', template: '<p>{{ message }}</p>' })
export class HelloComponent implements OnInit {
message: string;
ngOnInit(): void {
this.message = 'Component initialized!';
console.log('ngOnInit called');
}
}
ngDoCheck
Detects and acts upon changes that Angular can't or won't detect on its own. It's called immediately after ngOnChanges and ngOnInit, and on every subsequent change detection run. Use with caution as it can impact performance.
import { Component, DoCheck } from '@angular/core';
@Component({ selector: 'app-docheck', template: '<p>DoCheck component</p>' })
export class DoCheckComponent implements DoCheck {
ngDoCheck(): void {
console.log('ngDoCheck called');
// Implement custom change detection logic here
}
}
ngAfterContentInit
Responds after Angular projects external content into the component's view. This hook is called once after the first ngDoCheck.
import { Component, AfterContentInit, ContentChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-parent-content',
template: `
<p>Parent Content</p>
<ng-content></ng-content>
`
})
export class ParentContentComponent implements AfterContentInit {
@ContentChild('projectedContent') projectedContent: ElementRef;
ngAfterContentInit(): void {
console.log('ngAfterContentInit called. Projected content:', this.projectedContent?.nativeElement.textContent);
}
}
ngAfterContentChecked
Responds after Angular checks the content projected into the component. Called after ngAfterContentInit and every subsequent ngDoCheck.
import { Component, AfterContentChecked } from '@angular/core';
@Component({ selector: 'app-checked-content', template: '<ng-content></ng-content>' })
export class CheckedContentComponent implements AfterContentChecked {
ngAfterContentChecked(): void {
console.log('ngAfterContentChecked called');
}
}
ngAfterViewInit
Responds after Angular initializes the component's views and child views. This hook is called once after the first ngAfterContentChecked.
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-view-init',
template: `
<p #viewElement>This is part of the view.</p>
`
})
export class ViewInitComponent implements AfterViewInit {
@ViewChild('viewElement') viewElement: ElementRef;
ngAfterViewInit(): void {
console.log('ngAfterViewInit called. View element:', this.viewElement.nativeElement.textContent);
}
}
ngAfterViewChecked
Responds after Angular checks the component's views and child views. Called after ngAfterViewInit and every subsequent ngAfterContentChecked.
import { Component, AfterViewChecked } from '@angular/core';
@Component({ selector: 'app-view-checked', template: '<p>View Checked Component</p>' })
export class ViewCheckedComponent implements AfterViewChecked {
ngAfterViewChecked(): void {
console.log('ngAfterViewChecked called');
}
}
ngOnDestroy
Cleans up just before Angular destroys the component or directive. This is the place to unsubscribe from observables, detach event handlers, and prevent memory leaks. It's called just before Angular destroys the directive/component.
import { Component, OnDestroy } from '@angular/core';
import { Subscription, interval } from 'rxjs';
@Component({ selector: 'app-destroy', template: '<p>Destroy Component</p>' })
export class DestroyComponent implements OnDestroy {
private timerSubscription: Subscription;
constructor() {
this.timerSubscription = interval(1000).subscribe(num => console.log('Timer:', num));
}
ngOnDestroy(): void {
console.log('ngOnDestroy called: Cleaning up resources');
if (this.timerSubscription) {
this.timerSubscription.unsubscribe();
}
}
}
Order of Execution
The lifecycle hooks execute in a predictable sequence. For components, content hooks are called before view hooks, as content is projected before the component's own view is fully initialized. Changes to data-bound input properties trigger ngOnChanges.
- ngOnChanges (when input properties change)
- ngOnInit
- ngDoCheck
- ngAfterContentInit
- ngAfterContentChecked
- ngAfterViewInit
- ngAfterViewChecked
- ngOnDestroy (when component is destroyed)
Lifecycle Hooks Summary
| Hook | Purpose | When Called |
|---|---|---|
| ngOnChanges | Respond when Angular sets/resets data-bound input properties. | Before ngOnInit and on input changes. |
| ngOnInit | Initialize the component/directive after Angular first displays data-bound properties. | Once after ngOnChanges and component initialization. |
| ngDoCheck | Detect and act upon changes not detected by Angular's default change detection. | Immediately after ngOnChanges/ngOnInit and on every subsequent change detection run. |
| ngAfterContentInit | Respond after Angular projects external content into the component's view. | Once after the first ngDoCheck. |
| ngAfterContentChecked | Respond after Angular checks the content projected into the component. | After ngAfterContentInit and every subsequent ngDoCheck. |
| ngAfterViewInit | Respond after Angular initializes the component's views and child views. | Once after the first ngAfterContentChecked. |
| ngAfterViewChecked | Respond after Angular checks the component's views and child views. | After ngAfterViewInit and every subsequent ngAfterContentChecked. |
| ngOnDestroy | Clean up just before Angular destroys the component/directive. | Just before Angular destroys the component/directive. |