NashTech Insights

Understanding Parent-Child Component Interactions with @Input and @Output Decorators

Alka Vats
Alka Vats
Table of Contents

Angular, a robust and widely-used web framework, empowers developers to build dynamic and scalable applications. One of its powerful features is the ability to create modular and reusable components, and these components often need to communicate with each other. Angular facilitates this communication through the use of @Input and @Output decorator, enabling parent-child interactions seamlessly. In this blog post, we’ll delve into the intricacies of this decorator, providing examples and insights to help you master Angular’s component communication.

If you want to learn one more angular feature, you can refer here.

Understanding Parent-Child Component Relationship

Before we delve into the details of @Input and @Output decorators, let’s understand the parent-child component relationship in Angular. In a typical scenario, you may have a parent component that encapsulates one or more child components. Communication between these components can be crucial for passing data from the parent to the child or vice versa.

@Input Decorator

The @Input decorator allows a parent component to pass data to a child component. It essentially binds a property of the child component to a property of the parent component. Here’s an example to illustrate how it works:

Parent Component

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

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child [message]="parentMessage"></app-child>
  `,
})
export class ParentComponent {
  parentMessage = 'Message from Parent';
}

Child Component

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

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

In this example, the ParentComponent passes the parentMessage to the ChildComponent using the [message] binding. The @Input decorator in the child component’s message property makes this communication possible.

@Output Decorator

Conversely, the @Output decorator enables communication from a child component to a parent component. It emits custom events that the parent component can listen to. Let’s illustrate this with an example:

Child Component

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

@Component({
  selector: 'app-child',
  template: `
    <button (click)="sendMessage()">Send Message to Parent</button>
  `,
})
export class ChildComponent {
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Message from Child');
  }
}

Parent Component

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

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child (messageEvent)="receiveMessage($event)"></app-child>
    <p>{{ receivedMessage }}</p>
  `,
})
export class ParentComponent {
  receivedMessage = '';

  receiveMessage(message: string) {
    this.receivedMessage = message;
  }
}

In this example, the ChildComponent emits a custom event using the messageEvent property decorated with @Output. The parent component then listens to this event and handles it with the receiveMessage method.

Now, let’s dive deeper into Angular’s @Input and @Output decorators, exploring additional concepts, best practices, and advanced use cases.

Advanced Usage of @Input

1. Input Alias

You can use the @Input decorator to set an alias for the property, providing a more expressive and meaningful name in the child component. Consider the following example:

Parent Component

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

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child [externalMessage]="parentMessage"></app-child>
  `,
})
export class ParentComponent {
  parentMessage = 'Message from Parent';
}

Child Component

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

@Component({
  selector: 'app-child',
  template: `
    <h2>Child Component</h2>
    <p>{{ internalMessage }}</p>
  `,
})
export class ChildComponent {
  @Input('externalMessage') internalMessage: string = '';
}

In this example, the parent component binds parentMessage to the child component using [externalMessage]. However, within the child component, the property is named internalMessage.

2. Using Setter with @Input

You can use a setter method with @Input to perform additional logic when the input property changes. This is useful when you need to react to changes and take some action.

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

@Component({
  selector: 'app-child',
  template: `
    <h2>Child Component</h2>
    <p>{{ internalMessage }}</p>
  `,
})
export class ChildComponent implements OnChanges {
  private _internalMessage: string = '';

  @Input()
  set internalMessage(value: string) {
    // Additional logic, if needed
    this._internalMessage = value.toUpperCase();
  }

  get internalMessage(): string {
    return this._internalMessage;
  }

  ngOnChanges(changes: SimpleChanges): void {
    // Handle changes if necessary
  }
}

In this example, the internalMessage property is set using the setter, allowing for custom logic (in this case, converting the message to uppercase).

Advanced Usage of @Output

1. EventEmitter with Custom Types

@Output can emit custom events with specific data types. This adds type safety to your events. Consider the following example:

Child Component

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

@Component({
  selector: 'app-child',
  template: `
    <button (click)="sendMessage()">Send Message to Parent</button>
  `,
})
export class ChildComponent {
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Message from Child');
  }
}

Parent Component

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

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child (messageEvent)="receiveMessage($event)"></app-child>
    <p>{{ receivedMessage }}</p>
  `,
})
export class ParentComponent {
  receivedMessage = '';

  receiveMessage(message: string) {
    this.receivedMessage = message;
  }
}

In this example, the messageEvent emits a string, making the event more explicit and readable.

2. EventEmitter with @ViewChild

You can use @ViewChild to get a reference to the child component in the parent component and subscribe to its events directly.

Parent Component

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child></app-child>
    <p>{{ receivedMessage }}</p>
  `,
})
export class ParentComponent implements AfterViewInit {
  @ViewChild(ChildComponent) childComponent!: ChildComponent;
  receivedMessage = '';

  ngAfterViewInit(): void {
    this.childComponent.messageEvent.subscribe((message: string) => {
      this.receivedMessage = message;
    });
  }
}

In this example, @ViewChild is used to get a reference to the ChildComponent, and the parent component subscribes directly to the messageEvent emitted by the child.

Conclusion

Understanding the advanced features and best practices of @Input and @Output in Angular allows you to build more flexible and maintainable components. Whether it’s using aliases, setters, or advanced event handling, these techniques empower you to create sophisticated and responsive Angular applications. As you continue to explore and apply these concepts, you’ll find that Angular’s component-based architecture becomes an even more powerful tool in your development arsenal. Happy coding!

Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.

Alka Vats

Alka Vats

Alka Vats is a Software Consultant at Nashtech. She is passionate about web development. She is recognized as a good team player, a dedicated and responsible professional, and a technology enthusiast. She is a quick learner & curious to learn new technologies. Her hobbies include reading books, watching movies, and traveling.

Leave a Comment

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

Suggested Article

%d