[Angular 16] Input Property Binding, Passing and Detecting Change in Data

In Angular applications, communication across various components plays a vital role in developing robust and modular architecture. One of the most useful ways to pass data from parent to child components is by using the @Input property binding. In this article, we will explore how to efficiently use the @Input decorator to pass values of…

By.

•

min read

In Angular applications, communication across various components plays a vital role in developing robust and modular architecture. One of the most useful ways to pass data from parent to child components is by using the @Input property binding.

In this article, we will explore how to efficiently use the @Input decorator to pass values of different types like Data, Array, Objects or functions from parent to child.

Angular @Input Property Binding, Passing and Detecting Change in Data

[lwptoc]

We will also discuss in-depth related topics like how to detect changes in the Input values in a child, and how to manage the performance of the application when passing data from parent to child using @Input property binding techniques with simple examples.

Understanding @Input Property Binding

By using the @Input decorator in Angular, we can expose the properties of a child component and make it accessible from its parent component. We can easily setup a communication bridge from parent to child and also detect changes in the value from the child component.

How to Use @Input Decorator?

Let’s have a look at how to easily start using the @input decorators to pass data from parent to child component with a simple example below:

 

Define an Input Property in the Child Component

To receive data in the child component, we will first define a property using the @Input decorator. This property with @Input decorator defined will be the entry point to start fetching data from the parent component.

// child.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<p>{{ childValue }}</p>'
})
export class ChildComponent {
  @Input() childValue: string;
}

In the above code, we have defined the @Input() childValue of string type with null as the default value in our ChildComponent.

 

Pass Data from Parent to Child Component

Thereafter, in the parent component’s template, we can bind a value to the child component’s @Input property by using square brackets []. In this way, we can establish a connection between the parent and child components.

<!-- parent.component.html -->
<app-child [childValue]="parentData"></app-child>

In the above example, parentData is a property in the parent component that can hold the value that we want to pass to the child component.

 

Access the Input Value in the Child Component

Once the value is passed from the parent to the child component, we can access it in the child component’s class, template HTML, or any other part of the component.

// child.component.ts
export class ChildComponent {
  @Input() childValue: string;

  // You can use childValue in this component
}

 

Detecting Changes in Input Values

Sometimes, we may need to react or trigger operations in the child component, if there is any chnage in the Input value that is being passed or updated from the parent component.
For such purposes, Angular provides a lifecycle hook named ngOnChange. This hook keeps watch on changes in the Input variables and gets called if any change is detected.

Let’s have a look at how we can use the ngOnChanges hook to detect changes in the input value:

// child.component.ts
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<p>{{ childValue }}</p>'
})
export class ChildComponent implements OnChanges {
  @Input() childValue: string;

  ngOnChanges(changes: SimpleChanges) {
    if (changes.childValue) {
      console.log(`Child Value changed to: ${changes.childValue.currentValue}`);
    }
  }
}

Here we have defined the ngOnChanges hook, which returns the responses of type SimpleChanges. We can get all the Input properties in it. By adding the if expression we can specifically act on that particular Input property on which we want to control the behaviour.

 

Using @Input with Different Data Types

By using the @Input property binding, we can pass any type of data from the parent to the child component. Let’s have a quick look with examples of each in following sections:

 

1. Objects

We have already discussed on passing a simple text string from parent to child. But we can also pass an Object as shown below:

// child.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<p>{{ childObject.name }}</p>'
})
export class ChildComponent {
  @Input() childObject: { name: string };
}
// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: '<app-child [childObject]="parentObject"></app-child>'
})
export class ParentComponent {
  parentObject = { name: 'John' };
}

 

2. Arrays

Similarly, like objects, we can pass the Array items to the child component:

// child.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<ul><li *ngFor="let item of childArray">{{ item }}</li></ul>'
})
export class ChildComponent {
  @Input() childArray: string[];
}
// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: '<app-child [childArray]="parentArray"></app-child>'
})
export class ParentComponent {
  parentArray = ['Apple', 'Banana', 'Cherry'];
}

 

3. Functions

We cannot directly bind a function using @Input. However, we can pass a function reference from the parent to the child component as an input parameter:

// child.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<button (click)="executeFunction()">Call Function</button>'
})
export class ChildComponent {
  @Input() functionReference: () => void;

  executeFunction() {
    if (this.functionReference) {
      this.functionReference();
    }
  }
}
// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: '<app-child [functionReference]="parentFunction"></app-child>'
})
export class ParentComponent {
  parentFunction() {
    console.log('Function called from parent.');
  }
}

 

Performance Considerations with @Input()

When working with complex objects, it is important to keep a close watch on performance while using the @Input(). Frequent changes to the input properties may result in excessive chnage detection cycles and it can impact performance.

We can follow these techniques to maintain the efficiency of our application:

  • Use OnPush change detection strategy in child components.
  • Avoid deep object comparisons in ngOnChanges.
  • Use immutability to minimize changes to input objects.

 

Using OnPush Change Detection Strategy in Child Components

We can manipulate the change detection strategy which is known as OnPush. By using the OnPush strategy, we can tell Angular to run change detection only when the input property on that component chnage or any event is triggered.

Here is a quick example of how we can deploy OnPush chnage detection strategy in the Child component:

// child.component.ts
import { Component, Input, OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '<p>{{ childValue }}</p>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnChanges {
  @Input() childValue: string;

  constructor(private cdr: ChangeDetectorRef) {}

  ngOnChanges(changes: SimpleChanges) {
    if (changes.childValue) {
      console.log(`Child Value changed to: ${changes.childValue.currentValue}`);
      // Manually trigger change detection
      this.cdr.detectChanges();
    }
  }
}

Here we applied ChangeDetectionStrategy.OnPush, which can optimize the child component’s performance by reducing unnecessary change detection cycles, usually where not many changes happen on input values.

 

Conclusion

We have discussed how to use @Input decorator in Angular application to pass data of any type including String, Object, Array or Function references to the child component. Moreover, we can keep watch on any changes in the input values in the child component.

We also discussed the drawbacks of using @Input as it may hit the performance and their solution to use OnPush strategy to overcome the performance issues with easy examples

Leave a Reply

Your email address will not be published. Required fields are marked *