Introduction
Angular provides several lifecycle hooks that allow developers to execute custom logic at specific stages, such as initialization, change detection, rendering, and destruction.
In Angular 20+, lifecycle hooks continue to play a vital role alongside modern features such as standalone components, signals, and the latest rendering improvements. Whether you’re developing a small application or a large enterprise solution, mastering lifecycle hooks will help you write cleaner and more predictable code.
In this guide, you’ll learn what the Angular lifecycle is, why it matters, the purpose of every lifecycle hook, and best practices for using them effectively.
What is the Angular Lifecycle?
The Angular lifecycle refers to the sequence of events that occur from the creation of a component until its destruction.
Angular automatically performs several operations during a component’s lifetime, including:
- Creating the component instance
- Setting input properties
- Detecting data changes
- Rendering the component
- Checking child components
- Destroying the component
At each important stage, Angular provides lifecycle hooks that developers can implement to execute custom code.
Angular Component Lifecycle Flow
The lifecycle of a component generally follows this order:
Component Created
│
▼
Constructor
│
▼
ngOnChanges
│
▼
ngOnInit
│
▼
ngDoCheck
│
▼
ngAfterContentInit
│
▼
ngAfterContentChecked
│
▼
ngAfterViewInit
│
▼
ngAfterViewChecked
│
▼
(Change Detection Repeats)
│
▼
ngOnDestroy
Some hooks execute only once, while others are called repeatedly whenever Angular performs change detection.
Component Creation Phase
The lifecycle begins when Angular creates a component instance.
1. Constructor
The constructor is the first method executed. Its primary purpose is dependency injection.
Example:
import { Component } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-user',
template: `User Profile
`
})
export class UserComponent {
constructor(private userService: UserService) {
console.log('Constructor executed');
}
}
The constructor should not contain complex initialization logic because Angular has not yet initialized input properties.
Use the constructor for:
- Dependency injection
- Simple property initialization
Avoid:
- API calls
- Accessing @Input() values
- DOM manipulation
2. ngOnChanges
ngOnChanges() is called whenever an @Input() property changes.
It executes:
- Before ngOnInit()
- Every time input values change
Example:
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-profile',
template: `{{ name }}
`
})
export class ProfileComponent implements OnChanges {
@Input() name = '';
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
}
Typical use cases:
- Responding to parent component updates
- Refreshing displayed data
- Validating incoming values
3. ngOnInit
ngOnInit() is called once after Angular initializes all input properties.
This is the most commonly used lifecycle hook.
Example:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-dashboard',
template: `Dashboard
`
})
export class DashboardComponent implements OnInit {
ngOnInit(): void {
console.log('Component initialized');
}
}
Common tasks performed in ngOnInit() include:
- Loading data from APIs
- Initializing forms
- Setting default values
- Calling services
- Starting application logic
Unlike the constructor, all input properties are available here.
4. ngDoCheck
Angular automatically checks for data changes using change detection.
ngDoCheck() allows developers to implement custom change detection logic.
Example:
import { Component, DoCheck } from '@angular/core';
@Component({
selector: 'app-cart',
template: `Shopping Cart
`
})
export class CartComponent implements DoCheck {
ngDoCheck(): void {
console.log('Custom change detection');
}
}
Use this hook carefully because it executes frequently and can affect performance if heavy computations are performed.
Content Projection Lifecycle
Angular supports content projection using the <ng-content> element.
Two lifecycle hooks are specifically related to projected content.
1. ngAfterContentInit
Called once after projected content has been initialized.
Example:
ngAfterContentInit(): void {
console.log('Projected content initialized');
}
Typical use cases:
- Reading projected content
- Performing one-time initialization
2. ngAfterContentChecked
Runs after every check of projected content.
Example:
ngAfterContentChecked(): void {
console.log('Content checked');
}
This hook is useful for responding to updates in projected content but should avoid expensive operations because it executes repeatedly.
View Lifecycle
The view lifecycle concerns the component’s own template and child components.
1. ngAfterViewInit
Executed once after Angular initializes the component’s view and all child views.
Example:
import { ViewChild, AfterViewInit, ElementRef } from '@angular/core';
@ViewChild('title')
title!: ElementRef;
ngAfterViewInit(): void {
console.log(this.title.nativeElement.textContent);
}
Common uses:
- Accessing @ViewChild
- Working with DOM elements
- Initializing third-party libraries
- Measuring element sizes
2. ngAfterViewChecked
Called after Angular checks the component view.
Example:
ngAfterViewChecked(): void {
console.log('View checked');
}
Because this hook runs frequently, avoid placing heavy logic inside it.
ngOnDestroy
ngOnDestroy() is called immediately before Angular removes the component.
It is one of the most important lifecycle hooks because it prevents memory leaks.
Example:
import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-users',
template: `Users
`
})
export class UsersComponent implements OnDestroy {
subscription!: Subscription;
ngOnDestroy(): void {
this.subscription.unsubscribe();
console.log('Component destroyed');
}
}
Common cleanup tasks include:
- Unsubscribing from Observables
- Clearing timers
- Removing event listeners
- Closing WebSocket connections
- Releasing resources
Proper cleanup ensures applications remain efficient over time.
Complete Lifecycle Example
The following component demonstrates several lifecycle hooks together:
import { Component, Input, OnChanges, OnInit, DoCheck, AfterViewInit, OnDestroy, SimpleChanges
} from '@angular/core';
@Component({
selector: 'app-example',
template: `{{ title }}
`
})
export class ExampleComponent
implements
OnChanges,
OnInit,
DoCheck,
AfterViewInit,
OnDestroy {
@Input() title = '';
ngOnChanges(changes: SimpleChanges): void {
console.log('OnChanges', changes);
}
ngOnInit(): void {
console.log('OnInit');
}
ngDoCheck(): void {
console.log('DoCheck');
}
ngAfterViewInit(): void {
console.log('AfterViewInit');
}
ngOnDestroy(): void {
console.log('OnDestroy');
}
}
Running this component illustrates how Angular invokes each hook as the component is created, updated, and destroyed.
Best Practices
Follow these recommendations when working with Angular lifecycle hooks:
- Use the constructor only for dependency injection.
- Initialize application data inside ngOnInit().
- Keep ngDoCheck() lightweight to avoid performance issues.
- Access DOM elements only after ngAfterViewInit().
- Always unsubscribe from Observables or clean up resources in ngOnDestroy().
- Avoid duplicating logic across multiple hooks.
- Use lifecycle hooks only when needed to keep components simple and maintainable.
Common Mistakes
Developers new to Angular often make these mistakes:
1. Performing API Calls in the Constructor
The constructor should not be used for loading application data. Prefer ngOnInit() because inputs have already been initialized.
2. Forgetting Cleanup
Neglecting to unsubscribe from Observables or clear timers can lead to memory leaks and degraded performance.
3. Heavy Processing in Frequently Called Hooks
Hooks such as ngDoCheck(), ngAfterContentChecked(), and ngAfterViewChecked() are invoked repeatedly. Expensive calculations inside these hooks can slow down the application.
4. Accessing View Elements Too Early
Attempting to access @ViewChild references before ngAfterViewInit() may result in undefined values because the view has not been fully initialized.
Lifecycle Hooks Summary
| Lifecycle Hook | Called | Typical Use |
|---|---|---|
| Constructor | Component creation | Dependency injection |
| ngOnChanges | Input changes | Respond to updated inputs |
| ngOnInit | Once after initialization | Load data and initialize state |
| ngDoCheck | Every change detection cycle | Custom change detection |
| ngAfterContentInit | Once after projected content initialization | Initialize projected content |
| ngAfterContentChecked | After each projected content check | React to projected content updates |
| ngAfterViewInit | Once after view initialization | Access @ViewChild and DOM |
| ngAfterViewChecked | After each view check | Respond to view updates |
| ngOnDestroy | Before component destruction | Clean up subscriptions and resources |
Conclusion
The Angular component lifecycle provides a structured way to manage a component from creation to destruction. By understanding when each lifecycle hook is executed, developers can place their logic in the appropriate stage, leading to cleaner code, better performance, and fewer bugs.
While ngOnInit() is commonly used for initialization and ngOnDestroy() is essential for cleanup.
Angular Lifecycle – Interview Questions
Q 1: What is the Angular component lifecycle?
Q 2: What is ngOnInit?
Q 3: What is ngOnDestroy used for?
Q 4: What is ngOnChanges?
Q 5: Why are lifecycle hooks important?
Angular Lifecycle – Objective Questions (MCQs)
Q1. Which hook runs first?
Q2. ngOnInit() executes:
Q3. Cleanup logic is written in:
Q4. ngAfterViewInit() is called when:
Q5. Which hook detects input changes?