Angular Series Part 2 From Basics to Advanced: Exploring Angular’s ngOnChanges
Tags: webdev, javascript, angular, typescript
Published: 2024-05-29 14:01:32

# Understanding Angular's `ngOnChanges`: A Comprehensive Guide

{% embed https://www.youtube.com/embed/TSmj3yvC6jM %}

## Introduction

Angular, a powerful front-end framework, offers numerous lifecycle hooks to manage component behavior. Among these hooks, `ngOnChanges` is particularly important as it allows developers to react to changes in component input properties. Understanding how to use `ngOnChanges` effectively can significantly improve the efficiency and performance of Angular applications. This article will dive deep into the `ngOnChanges` lifecycle hook, providing step-by-step examples and covering various scenarios to ensure a thorough grasp of its usage.

## What Is `ngOnChanges`?

`ngOnChanges` is a lifecycle hook in Angular that is called whenever there are changes to input properties of a component. It allows you to act upon those changes and is useful for tasks that need to be executed when input values change.

### How Does `ngOnChanges` Work?

The `ngOnChanges` method is triggered when Angular sets or resets data-bound input properties. It receives a `SimpleChanges` object, which contains the current and previous values of the input properties.

### Syntax

```typescript
ngOnChanges(changes: SimpleChanges): void {
  // logic to handle changes
}
```

## Setting Up an Angular Project

Before diving into `ngOnChanges`, let's set up a basic Angular project. This will help us to follow along with the examples.

### Step 1: Create a New Angular Project

Run the following command to create a new Angular project:

```bash
ng new ngOnChangesDemo
cd ngOnChangesDemo
```

### Step 2: Generate a New Component

Generate a new component that we'll use to demonstrate `ngOnChanges`:

```bash
ng generate component demo
```

## Implementing `ngOnChanges`

Let's implement `ngOnChanges` in our newly created component to see how it works in practice.

### Example 1: Basic Usage of `ngOnChanges`

First, let's set up a parent component that will pass data to the `DemoComponent`.

#### Parent Component Template (app.component.html)

```html
<app-demo [inputValue]="parentValue"></app-demo>
<button (click)="changeValue()">Change Value</button>
```

#### Parent Component Class (app.component.ts)

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

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

  changeValue() {
    this.parentValue = Math.floor(Math.random() * 100);
  }
}
```

#### Child Component Template (demo.component.html)

```html
<p>Input Value: {{ inputValue }}</p>
```

#### Child Component Class (demo.component.ts)

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

@Component({
  selector: 'app-demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.css']
})
export class DemoComponent implements OnChanges {
  @Input() inputValue: number;

  ngOnChanges(changes: SimpleChanges) {
    for (let propName in changes) {
      let change = changes[propName];
      let cur = JSON.stringify(change.currentValue);
      let prev = JSON.stringify(change.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}
```

### Explanation

In this example:
- `DemoComponent` receives an input property `inputValue`.
- Whenever `inputValue` changes, the `ngOnChanges` method logs the current and previous values to the console.
- The parent component (`AppComponent`) has a button to change `parentValue`, demonstrating how `ngOnChanges` responds to changes in input properties.

### Example 2: Handling Multiple Input Properties

Let's extend the example to handle multiple input properties.

#### Parent Component Template (app.component.html)

```html
<app-demo [inputValue]="parentValue" [anotherValue]="parentAnotherValue"></app-demo>
<button (click)="changeValue()">Change Values</button>
```

#### Parent Component Class (app.component.ts)

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

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

  changeValue() {
    this.parentValue = Math.floor(Math.random() * 100);
    this.parentAnotherValue = 'Changed Value ' + Math.floor(Math.random() * 100);
  }
}
```

#### Child Component Template (demo.component.html)

```html
<p>Input Value: {{ inputValue }}</p>
<p>Another Value: {{ anotherValue }}</p>
```

#### Child Component Class (demo.component.ts)

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

@Component({
  selector: 'app-demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.css']
})
export class DemoComponent implements OnChanges {
  @Input() inputValue: number;
  @Input() anotherValue: string;

  ngOnChanges(changes: SimpleChanges) {
    for (let propName in changes) {
      let change = changes[propName];
      let cur = JSON.stringify(change.currentValue);
      let prev = JSON.stringify(change.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}
```

### Explanation

In this extended example:
- `DemoComponent` now has two input properties: `inputValue` and `anotherValue`.
- The `ngOnChanges` method logs changes to both properties.
- The parent component (`AppComponent`) changes both input values when the button is clicked, showcasing how `ngOnChanges` handles multiple property changes.

## Common Scenarios and Best Practices

### Scenario 1: Initial Value Setting

`ngOnChanges` is also called when the component is initialized if there are any input properties.

#### Example

If the parent component initially sets values for the inputs:

```html
<app-demo [inputValue]="42" [anotherValue]="'Hello'"></app-demo>
```

`ngOnChanges` will log these initial values when the component is first rendered.

### Scenario 2: Ignoring Unnecessary Changes

In some cases, you might want to ignore certain changes or perform actions only on specific changes.

#### Example

```typescript
ngOnChanges(changes: SimpleChanges) {
  if (changes['inputValue']) {
    let cur = JSON.stringify(changes['inputValue'].currentValue);
    let prev = JSON.stringify(changes['inputValue'].previousValue);
    console.log(`inputValue: currentValue = ${cur}, previousValue = ${prev}`);
  }
}
```

### Scenario 3: Deep Change Detection

`ngOnChanges` performs shallow comparison. For deep objects, additional logic is required.

#### Example

```typescript
import { isEqual } from 'lodash';

ngOnChanges(changes: SimpleChanges) {
  if (changes['complexObject']) {
    let cur = changes['complexObject'].currentValue;
    let prev = changes['complexObject'].previousValue;
    if (!isEqual(cur, prev)) {
      console.log(`complexObject has changed.`);
    }
  }
}
```

### Best Practices

1. **Minimize Heavy Processing:** Avoid performing heavy computations in `ngOnChanges`. Delegate them to other methods if necessary.
2. **Use Immutable Data Structures:** This helps in efficiently detecting changes.
3. **Combine with Other Lifecycle Hooks:** Use `ngOnInit` and `ngDoCheck` for initialization and custom change detection logic.

## FAQ Section

### What Is `ngOnChanges` Used For?

`ngOnChanges` is used to detect and respond to changes in input properties of a component. It is essential for tasks that need to react to input value changes dynamically.

### When Is `ngOnChanges` Called?

`ngOnChanges` is called before `ngOnInit` when the component is initialized and whenever any data-bound input properties change.

### How Does `ngOnChanges` Differ from `ngDoCheck`?

`ngOnChanges` is triggered automatically by Angular when input properties change, while `ngDoCheck` is called during every change detection cycle and can be used for custom change detection.

### Can `ngOnChanges` Be Used with All Input Properties?

Yes, `ngOnChanges` can be used with all input properties defined with the `@Input` decorator.

### What Is `SimpleChanges`?

`SimpleChanges` is an object that contains the current and previous values of the input properties. It is passed as an argument to the `ngOnChanges` method.

## Conclusion

Mastering `ngOnChanges` is crucial for developing dynamic and responsive Angular applications. By understanding its usage, handling multiple input properties, and applying best practices, developers can effectively manage component behavior based on changing inputs. This comprehensive guide provides the foundation needed to utilize `ngOnChanges` proficiently in your Angular projects.