Understanding ngOnChanges in Angular: Detecting Input Changes from Parent Components

Understanding ngOnChanges in Angular: Detecting Input Changes from Parent Components

In Angular, the ngOnChanges lifecycle hook is a powerful tool for tracking changes to @Input() properties passed from parent to child components. It enables developers to react to data updates, reset internal state, or trigger dependent logic in response to those changes.

 

What Is ngOnChanges?

The ngOnChanges() method is called whenever an @Input() property changes. It receives a SimpleChanges object that contains the previous and current values of all bound properties that have changed.

 

When to Use ngOnChanges

Here are 5 common use cases for ngOnChanges:

 

1. Reacting to Input Property Changes

When a child component receives new input and needs to perform actions like fetching related data.

 

@Input() userId: number;

 

ngOnChanges(changes: SimpleChanges) {

  if (changes['userId']) {

    this.loadUserData(this.userId);

  }

}

 

2. Resetting Component State

Reset internal fields, form states, or flags when an input value updates.

 

@Input() resetFormTrigger: boolean;

 

ngOnChanges(changes: SimpleChanges) {

  if (changes['resetFormTrigger'] && this.resetFormTrigger) {

    this.form.reset();

  }

}

 

3. Comparing Previous and Current Values

Useful for logging, audits, or conditional changes based on value differences.

 

ngOnChanges(changes: SimpleChanges) {

  const nameChange = changes['name'];

  if (nameChange) {

    console.log(`Name changed from ${nameChange.previousValue} to ${nameChange.currentValue}`);

  }

}

 

4. Conditional API Calls or DOM Updates

Trigger side effects such as API requests when input changes.

 

@Input() productId: string;

 

ngOnChanges(changes: SimpleChanges) {

  if (changes['productId'] && this.productId) {

    this.fetchProductDetails(this.productId);

  }

}

 

5. Cascading Dropdowns (Dependent Inputs)

Update UI based on dependent values (like state list based on country selection).

ts

CopyEdit

@Input() selectedCountry: string;

 

ngOnChanges(changes: SimpleChanges) {

  if (changes['selectedCountry']) {

    this.loadStatesForCountry(this.selectedCountry);

  }

}

 

Full Example: Parent to Child with ngOnChanges

1. Parent Component

 

// parent.component.ts

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-parent',

  template: `

    <h2>Parent Component</h2>

    <input [(ngModel)]="userName" placeholder="Enter name" />

    <button (click)="changeUser()">Update User</button>

 

    <app-child [name]="userName"></app-child>

  `

})

export class ParentComponent {

  userName: string = 'John';

 

  changeUser() {

    this.userName = this.userName + '!';

  }

}

 

2. Child Component

 

// child.component.ts

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

 

@Component({

  selector: 'app-child',

  template: `

    <h3>Child Component</h3>

    <p>Current Name: {{ name }}</p>

    <p *ngIf="previousName">Previous Name: {{ previousName }}</p>

  `

})

export class ChildComponent implements OnChanges {

  @Input() name: string = '';

  previousName: string | null = null;

 

  ngOnChanges(changes: SimpleChanges): void {

    if (changes['name']) {

      const change = changes['name'];

      this.previousName = change.previousValue;

      console.log(`Name changed from ${change.previousValue} to ${change.currentValue}`);

    }

  }

}

 

3. App Module Setup

 

// app.module.ts

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { FormsModule } from '@angular/forms';

 

import { AppComponent } from './app.component';

import { ParentComponent } from './parent.component';

import { ChildComponent } from './child.component';

 

@NgModule({

  declarations: [AppComponent, ParentComponent, ChildComponent],

  imports: [BrowserModule, FormsModule],

  bootstrap: [AppComponent]

})

export class AppModule {}

 

Using ngOnChanges with Nested Objects

Angular’s ngOnChanges only fires when object references change. If you're passing a nested object, such as a user object, you need to update it with a new reference.

Example

@Input() user: { name: string; age: number };

 

ngOnChanges(changes: SimpleChanges): void {

  if (changes['user']) {

    console.log('User changed:', changes['user'].previousValue, '→', changes['user'].currentValue);

  }

}

Tip: Use this.user = { ...this.user } in the parent to trigger change detection.

 

Summary: 

Use Case

Description

React to data changes

Fetch data or run logic on input change

Reset child state

Clear forms or flags based on triggers

Compare old vs new input values

Useful for logs, validations, conditional updates

Trigger chained UI/API logic

E.g., update dropdowns, re-fetch on ID change

Handle nested objects

Requires reference change to detect updates

 

Comments

Popular posts from this blog

Promises in Angular

Mastering Your Angular Workflow: Essential CLI Commands for Efficient Development

Observables in Angular