ngDoCheck() is an Angular lifecycle hook that allows a component or directive to perform custom change detection.
Angular calls ngDoCheck() whenever it runs change detection for that component.
ngDoCheck(): void {
// Custom change-detection logic
}
It comes from Angular's DoCheck lifecycle interface:
import { DoCheck } from '@angular/core';
Simple definition:
ngDoCheck()lets us manually check for changes that Angular's normal lifecycle mechanisms may not directly expose in the way we need.
Why do we need ngDoCheck()?
Normally, Angular automatically detects changes and updates the UI.
For example:
name = 'Syed';
If name changes:
this.name = 'Mohamed';
Angular updates the view automatically.
So, most applications do not need ngDoCheck().
It becomes useful when we need custom logic during Angular's change-detection cycle, especially when monitoring changes that aren't conveniently handled by ngOnChanges().
For example, suppose a component has an object:
user = {
name: 'Syed',
city: 'Erode'
};
Later, only a property is modified:
this.user.name = 'Mohamed';
The object reference remains the same.
If this object were passed to a child through @Input(), ngOnChanges() is primarily associated with changes to the input binding value/reference. ngDoCheck() can be used when you need your own checking logic for such internal mutations.
Full Simple Sample Program
Let's create a parent component that passes a user object to a child.
app.ts — Parent
import { Component } from '@angular/core';
import { UserComponent } from './user';
@Component({
selector: 'app-root',
standalone: true,
imports: [UserComponent],
template: `
<h2>Parent Component</h2>
<button (click)="changeName()">
Change Name
</button>
<app-user [user]="user"></app-user>
`
})
export class App {
user = {
name: 'Syed',
city: 'Erode'
};
changeName() {
this.user.name = 'Mohamed';
}
}
user.ts — Child
import {
Component,
DoCheck,
Input
} from '@angular/core';
@Component({
selector: 'app-user',
standalone: true,
template: `
<h2>Child Component</h2>
<p>Name: {{ user.name }}</p>
<p>City: {{ user.city }}</p>
`
})
export class UserComponent implements DoCheck {
@Input() user!: {
name: string;
city: string;
};
previousName = '';
ngDoCheck(): void {
if (this.user.name !== this.previousName) {
console.log(
'Name changed:',
this.previousName,
'->',
this.user.name
);
this.previousName = this.user.name;
}
}
}
Explanation
Initially:
user = {
name: 'Syed',
city: 'Erode'
};
The parent sends the object to the child:
<app-user [user]="user"></app-user>
The child receives it:
@Input() user!: {
name: string;
city: string;
};
When we click:
<button (click)="changeName()">
this executes:
this.user.name = 'Mohamed';
Notice that we are not creating a new object.
We are modifying a property of the existing object.
Conceptually:
Before
user ──────► Object A
name = Syed
After
user ──────► Object A
name = Mohamed
The reference is still:
Object A
Our ngDoCheck() performs a custom comparison:
if (this.user.name !== this.previousName)
If the name changed:
console.log(...);
and then stores the latest value:
this.previousName = this.user.name;
ngOnChanges() vs ngDoCheck()
This is an important interview distinction.
ngOnChanges() |
ngDoCheck() |
|---|---|
Designed to react to @Input() binding changes |
Used for custom change-detection logic |
Receives SimpleChanges |
Does not receive SimpleChanges |
| Convenient for changed input values/references | Can manually inspect object properties/collections |
| Called when Angular detects input changes | Called during change-detection checks |
| Usually preferred when sufficient | Use only when custom checking is necessary |
For example:
this.user = {
name: 'Mohamed',
city: 'Erode'
};
Here we created a new object reference, which is straightforward for ngOnChanges() to observe as an input change.
But:
this.user.name = 'Mohamed';
mutates the existing object. If you specifically need lifecycle logic for that internal mutation, ngDoCheck() can perform your own comparison.
Advantages
1. Custom change detection
You have control over what should be checked.
if (this.user.name !== this.previousName)
2. Useful for complex objects
It can help detect specific internal mutations in:
Object
Array
Collection
3. More control
You can implement application-specific checking logic that isn't naturally expressed through ngOnChanges().
Disadvantages
The biggest disadvantage is performance.
ngDoCheck() can run very frequently because Angular invokes it during change-detection cycles.
For example:
ngDoCheck() {
console.log('Checking...');
}
You may see this logged many times.
Therefore, avoid expensive operations such as:
ngDoCheck() {
// Avoid expensive work here
this.loadHugeData();
this.callApi();
this.performComplexCalculation();
}
In particular, do not call APIs from ngDoCheck() just because a value might have changed. It can cause repeated requests.
When should we use ngDoCheck()?
Use it when:
- You genuinely need custom change detection
- You need to inspect specific internal changes to objects or collections
ngOnChanges()does not provide the behavior you need
Avoid it when normal Angular mechanisms are enough.
In modern Angular, you should generally first consider normal bindings, immutable updates, signals, computed values, effects, or other appropriate reactive patterns before implementing manual checking in ngDoCheck().
Lifecycle Position
A simplified lifecycle sequence is:
Component Created
↓
ngOnChanges()
↓
ngOnInit()
↓
ngDoCheck()
↓
ngAfterContentInit()
↓
ngAfterContentChecked()
↓
ngAfterViewInit()
↓
ngAfterViewChecked()
During later change-detection cycles:
Change Detection
↓
ngDoCheck()
↓
Content Checked
↓
View Checked
So ngDoCheck() is not called only once.
It can execute repeatedly.
Key Points
ngDoCheck()is an Angular lifecycle hook.- It is used for custom change-detection logic.
- It is called during Angular's change-detection checks.
- It can be useful for detecting specific internal mutations in objects or arrays.
- Unlike
ngOnChanges(), it does not receiveSimpleChanges. - It can run very frequently.
- Keep the code inside
ngDoCheck()lightweight. - Avoid API calls or expensive calculations inside it.
- Use it only when Angular's normal/reactive mechanisms aren't sufficient.
Interview Questions and Answers
1. What is ngDoCheck()?
ngDoCheck() is an Angular lifecycle hook used to implement custom change-detection logic. Angular calls it during change-detection checks for the component or directive.
2. Why do we use ngDoCheck()?
We use it when we need to manually inspect changes that aren't conveniently handled through standard input-change handling such as ngOnChanges().
3. What is the difference between ngOnChanges() and ngDoCheck()?
ngOnChanges() reacts to changes in input bindings and provides SimpleChanges. ngDoCheck() runs during change detection and allows us to implement our own checking logic.
4. Is ngDoCheck() called only once?
No. It can be called many times throughout the component's lifetime as Angular performs change detection.
5. Can we call an API inside ngDoCheck()?
Technically possible, but it is generally a bad practice because ngDoCheck() can execute frequently and could trigger repeated API requests.
6. Does every Angular component need ngDoCheck()?
No. Most components do not need it. Angular's normal change detection and modern reactive APIs handle most scenarios.
Interview one-line answer
ngDoCheck()is an Angular lifecycle hook that runs during change detection and allows developers to implement custom logic for detecting changes that require manual inspection.