Sharing Data Between Child and Parent Components in Angular

One common pattern in Angular development is sharing data between parent and child components. This can be achieved using the @Input() and @Output() decorators, which allow seamless communication between these components.

Using @Input() and @Output() for Component Communication

The @Input() decorator enables a parent component to send data to its child, while @Output() allows the child component to send data back to the parent. These decorators create a powerful way to manage component interaction in Angular applications.

Example of Component Hierarchy

In a typical component structure:

<parent-component>
  <child-component></child-component>
</parent-component>

The <parent-component> acts as the host for the <child-component>. With @Input() and @Output(), the parent can pass data to the child, and the child can communicate events back to the parent.

@Input(): Sending Data to a Child Component

The @Input() decorator in Angular is used to receive data from the parent component. To configure this, both the parent and child components need to be set up properly.

1. Configuring the Child Component

To use @Input() in a child component, import Input from @angular/core and decorate the property you want to bind.

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

export class ItemDetailComponent {
  @Input() item = ''; // The property 'item' receives data from the parent
}

In this example, @Input() decorates the item property, which is of type string. However, @Input() can accept various types like numbers, booleans, objects, etc.

2. Using @Input() in the Child Template

In the child component’s template, display the received data:

<p>Today's item: {{item}}</p>

3. Configuring the Parent Component

Next, bind the child component’s item property to the parent component’s data.

<app-item-detail [item]="currentItem"></app-item-detail>

In the parent component’s class, define the currentItem value:

export class AppComponent {
  currentItem = 'Television'; // Pass this value to the child component
}

Now, Angular passes the value of currentItem to the child component, rendering “Television” in the child.

@Output(): Sending Data to a Parent Component

The @Output() decorator allows child components to send data to the parent. This is typically done by raising an event.

1. Configuring the Child Component

In the child component class, decorate a property with @Output() and assign it an EventEmitter:

import { Component, Output, EventEmitter } from '@angular/core';

export class ItemOutputComponent {
  @Output() newItemEvent = new EventEmitter<string>(); // Emits string data to the parent

  addNewItem(value: string) {
    this.newItemEvent.emit(value); // Sends the value to the parent
  }
}

2. Child Template

The child component’s template might look like this:

<label for="item-input">Add an item:</label>
<input type="text" id="item-input" #newItem>
<button (click)="addNewItem(newItem.value)">Add to parent's list</button>

When the user clicks the button, the addNewItem() method emits the value to the parent.

3. Configuring the Parent Component

In the parent component, define a method to handle the event and add the item to a list:

export class AppComponent {
  items = ['item1', 'item2', 'item3'];

  addItem(newItem: string) {
    this.items.push(newItem);
  }
}

Bind the event in the parent’s template:

<app-item-output (newItemEvent)="addItem($event)"></app-item-output>

<ul>
  <li *ngFor="let item of items">{{item}}</li>
</ul>

When the user adds a new item in the child component, it’s pushed to the parent’s items array and rendered in the list.

Using @Input() and @Output() Together

You can use both @Input() and @Output() in the same child component to achieve two-way communication. For example:

<app-input-output
  [item]="currentItem"
  (deleteRequest)="crossOffItem($event)">
</app-input-output>

In this setup, the item input property receives data from the parent, and the deleteRequest output event sends data back to the parent when triggered.

Advanced Configurations

1. Marking an @Input() as Required

To make an @Input() property required, you can use the required metadata:

@Input({required: true}) item!: string; // Requires 'item' to be passed from the parent

If the parent component doesn’t pass this property, Angular throws a compile-time error.

2. Transforming an @Input() Property

To transform a property (e.g., from string to boolean), use the booleanAttribute transform function:

@Input({transform: booleanAttribute}) itemAvailability!: boolean; // Transforms 'itemAvailability' to boolean

This helps manage different types of input data effectively.

By utilizing Angular’s @Input() and @Output() decorators, developers can build highly interactive and dynamic applications. These decorators allow seamless data flow between components, providing flexibility and power in handling component communication.

Keep Learning 🙂

Leave a Reply

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