Angular Series Part 2 Mastering Angular’s ngOnChanges: A Comprehensive Guide

Chintanonweb
6 min readMay 29, 2024

Comprehensive Guide to Angular ngOnChanges with Step-by-Step Examples

Introduction

Angular is a robust front-end framework that allows developers to create dynamic and responsive web applications. One of its powerful features is the lifecycle hook mechanism, which gives developers fine-grained control over their components. Among these hooks, ngOnChanges stands out for its ability to detect and respond to changes in component input properties. In this guide, we'll explore ngOnChanges in detail, demonstrating its usage with practical examples and covering various scenarios.

Understanding ngOnChanges

ngOnChanges is a lifecycle hook in Angular that is called whenever one or more data-bound input properties of a component change. This hook is particularly useful when you need to act on changes to the input properties, such as updating a view or making a new API call.

The method signature for ngOnChanges is as follows:

ngOnChanges(changes: SimpleChanges): void

The changes parameter is an object of type SimpleChanges, which provides the current and previous values of the input properties that have changed.

Setting Up the Project

Before diving into the examples, let’s set up a basic Angular project. If you don’t already have Angular CLI installed, you can install it using npm:

npm install -g @angular/cli

Create a new Angular project:

ng new ngOnChangesDemo
cd ngOnChangesDemo
ng serve

Open the project in your preferred code editor.

Basic Example of ngOnChanges

We’ll start with a simple example to demonstrate how ngOnChanges works. Create a new component using Angular CLI:

ng generate component simple

Modify the simple.component.ts file as follows:

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

@Component({
selector: 'app-simple',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnChanges {
@Input() inputProperty: string;
ngOnChanges(changes: SimpleChanges): void {
console.log('ngOnChanges called');
console.log(changes);
}
}

In the parent component, use the app-simple selector and bind an input property:

<!-- app.component.html -->
<div>
<h1>ngOnChanges Basic Example</h1>
<input [(ngModel)]="parentProperty" placeholder="Enter a value">
<app-simple [inputProperty]="parentProperty"></app-simple>
</div>

Modify the app.component.ts file to include parentProperty:

// app.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentProperty: string = '';
}

Now, when you type in the input field, the ngOnChanges method in SimpleComponent will be called, logging the changes to the console.

Using ngOnChanges to Update the View

Next, let’s modify our example to update the view when the input property changes. Update the simple.component.html file:

<!-- simple.component.html -->
<p>Current Value: {{ currentValue }}</p>
<p>Previous Value: {{ previousValue }}</p>

And update simple.component.ts to track and display the current and previous values:

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

@Component({
selector: 'app-simple',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnChanges {
@Input() inputProperty: string;
currentValue: string;
previousValue: string;
ngOnChanges(changes: SimpleChanges): void {
if (changes['inputProperty']) {
this.previousValue = changes['inputProperty'].previousValue;
this.currentValue = changes['inputProperty'].currentValue;
}
}
}

Now, as you type in the input field, the view will update to show the current and previous values of inputProperty.

Handling Multiple Input Properties

ngOnChanges can handle multiple input properties simultaneously. Let's extend our component to handle two input properties. Update simple.component.ts:

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

@Component({
selector: 'app-simple',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnChanges {
@Input() inputProperty: string;
@Input() anotherInputProperty: string;
currentValue1: string;
previousValue1: string;
currentValue2: string;
previousValue2: string;
ngOnChanges(changes: SimpleChanges): void {
if (changes['inputProperty']) {
this.previousValue1 = changes['inputProperty'].previousValue;
this.currentValue1 = changes['inputProperty'].currentValue;
}
if (changes['anotherInputProperty']) {
this.previousValue2 = changes['anotherInputProperty'].previousValue;
this.currentValue2 = changes['anotherInputProperty'].currentValue;
}
}
}

Update the parent component template to bind the second input property:

<!-- app.component.html -->
<div>
<h1>ngOnChanges with Multiple Inputs</h1>
<input [(ngModel)]="parentProperty" placeholder="Enter first value">
<input [(ngModel)]="anotherParentProperty" placeholder="Enter second value">
<app-simple [inputProperty]="parentProperty" [anotherInputProperty]="anotherParentProperty"></app-simple>
</div>

And update the app.component.ts:

// app.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentProperty: string = '';
anotherParentProperty: string = '';
}

Now, changes to either input field will be reflected in the SimpleComponent, demonstrating the capability of ngOnChanges to handle multiple inputs.

Detecting Specific Changes

Sometimes, you might want to perform an action only when a specific property changes to a particular value. For this, you can add conditional logic inside ngOnChanges. Let's modify our example to trigger an alert when inputProperty changes to 'alert'.

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

@Component({
selector: 'app-simple',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnChanges {
@Input() inputProperty: string;
@Input() anotherInputProperty: string;
currentValue1: string;
previousValue1: string;
currentValue2: string;
previousValue2: string;
ngOnChanges(changes: SimpleChanges): void {
if (changes['inputProperty']) {
this.previousValue1 = changes['inputProperty'].previousValue;
this.currentValue1 = changes['inputProperty'].currentValue;
if (this.currentValue1 === 'alert') {
alert('Alert triggered by inputProperty change!');
}
}
if (changes['anotherInputProperty']) {
this.previousValue2 = changes['anotherInputProperty'].previousValue;
this.currentValue2 = changes['anotherInputProperty'].currentValue;
}
}
}

Now, when inputProperty changes to 'alert', an alert box will pop up.

Optimizing Performance

Using ngOnChanges can be powerful, but it’s important to consider performance implications, especially if the component has complex logic or the application is large. Here are a few tips to optimize performance:

  1. Minimize Heavy Processing: Avoid heavy processing inside ngOnChanges. If necessary, use debounce techniques to delay actions until changes settle.
  2. Conditional Checks: Only execute code when necessary by checking if the relevant properties have changed.
  3. Pure Pipes: Use pure pipes for simple transformations instead of handling everything in ngOnChanges.

Real-World Scenario: Fetching Data on Input Change

In real-world applications, you might want to fetch data from a server when an input property changes. Let’s create an example where changing an input property triggers a data fetch.

First, install HttpClientModule by adding it to app.module.ts:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
declarations: [
// ... other declarations
],
imports: [
// ... other imports
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Create a service for fetching data:

// data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
fetchData(query: string): Observable<any> {
return this.http.get(`https://api.example.com/data?query=${query}`);
}
}

Update simple.component.ts to use the data service:

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { DataService } from '../data.service';

@Component({
selector: 'app-simple',
templateUrl: './simple.component.html',
styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnChanges {
@Input() inputProperty: string;
data: any;
constructor(private dataService: DataService) { }
ngOnChanges(changes: SimpleChanges): void {
if (changes['inputProperty'] && changes['inputProperty'].currentValue) {
this.fetchData(changes['inputProperty'].currentValue);
}
}
fetchData(query: string): void {
this.dataService.fetchData(query).subscribe(response => {
this.data = response;
});
}
}

Update simple.component.html to display the fetched data:

<!-- simple.component.html -->
<div>
<p>Data: {{ data | json }}</p>
</div>

Now, when the input property changes, the component will fetch data from the server and display it.

Frequently Asked Questions

Q. What is ngOnChanges?

ngOnChanges is an Angular lifecycle hook called when any data-bound input property of a component changes.

Q. When should I use ngOnChanges?

Use ngOnChanges when you need to perform actions or update the view in response to changes in input properties.

Q. Can ngOnChanges handle multiple input properties?

Yes, ngOnChanges can handle changes to multiple input properties simultaneously.

Q. How can I optimize ngOnChanges for performance?

To optimize ngOnChanges, minimize heavy processing, use conditional checks, and consider using pure pipes for simple transformations.

Is ngOnChanges the only way to detect input changes?

While ngOnChanges is a primary method for detecting input changes, you can also use observables and other reactive programming techniques for more complex scenarios.

Conclusion

Understanding and effectively using ngOnChanges is crucial for creating dynamic and responsive Angular applications. By following the examples and best practices outlined in this guide, you can harness the full power of this lifecycle hook to build better, more efficient components. Whether you're handling simple input changes or fetching data from a server, ngOnChanges provides the flexibility you need to respond to changes in your application's state.

--

--

Chintanonweb

As a software engineer, bringing my ideas to life through code and inspiring others with the possibilities. Managed By : chintandhokai97@gmail.com