DEV Community

Cover image for Component Communication in Angular: Input(), Output()
Wayne Gakuo
Wayne Gakuo

Posted on

Component Communication in Angular: Input(), Output()

Angular components communicate using specific patterns based on their relationship (parent-to-child, sibling, or unrelated). The most common methods are @Input() and @Output() decorators, but newer features like Signals and Model Inputs offer modern alternatives.

Classic approach with Decorators

Before Angular v17, we used to pass information from the parent to the child component and vice versa by using the @Input() and @Output() decorators. To pass information to a child component (from the parent), we need to pass it through brackets [product]="productData". If we need to receive data in our parent component, we need to assign it as (addToCart)="addProductToCart($event)" to handle the event.

Child Component:

// Component with traditional `Input` and `Output`.
...
@Component({
  selector: 'app-product-card'
  template: `
    <div class="product-card">
      <img [ngSrc]="product.image" width="200" height="200">
    </div>
    ...
    <button (click)="onAddToCart($event)"> Add To Cart </button>
  `
})
class ProductCardComponent{
  // Receives data from parent.
  @Input() productData!: Product;

  // Sends data to parent.
  @Output() addToCart= new EventEmitter<Product>();

   onAddToCart(event: MouseEvent): void {
    // prevents the click event from bubbling up to the parent component and only emits the product
    event.stopPropagation();

    // emit the product to the parent component
    this.addToCart.emit(this.product);
  }
}
...
Enter fullscreen mode Exit fullscreen mode

Parent Component:

...
@Component({
  selector: 'app-product-page'
  template: `
    <app-product-card [product]="productData" (addToCart)="addToCart($event)">
  `
})
class ProductPageComponent{
  ...
  // Receives the event from the child and adds product to cart
   addToCart(product: Product){
    this.cartService.addToCart(product);
  }
}

Enter fullscreen mode Exit fullscreen mode

Modern Approach with input() and output()

Introduced in Angular v17.3, made stable and production ready by Angular v19, the input() signal function and the output() *function *(not a signal) were introduced. This offers better performance, improved change detection and smooth integration with Signals. This also provides much cleaner code to work with.

Below is a code snippet of the child component using the new approach using the input() signal and output() function. The parent component remains unchanged.

// Component with modern `Input` and `Output`.
@Component({...})
class ProductCardComponent{
  // Receives data from parent - using input signals
  product = input<Product>();

  // Sends data to parent - using output function
  addToCart = output<Product>();

   onAddToCart(event: MouseEvent): void {
     ...
     // emit the product to the parent component
     this.addToCart.emit(this.product);
  }
}

Enter fullscreen mode Exit fullscreen mode

Here are some notable changes from the above code snippet:

  • input() function declares a signal. This automatically updates when the parent component changes the value of the input.

  • output() expressions are used over the @Output() decorator.

  • No EventEmitter anymore.

  • No need to use the ngOnChanges lifecycle hook to track changes. Instead, it is recommended to use computed and effect when working signal-based inputs.

Migration to Signal Inputs and Output Function

The Angular CLI provides schematics that help you to automatically migrate your project from the classic @Input() and @Output() to the new input() signal function and ouptut() function.

ng generate @angular/core:signal-input-migration
ng generate @angular/core:output-migration
Enter fullscreen mode Exit fullscreen mode

These commands will:

  • Convert the @Input() properties to the signal-based input().

  • Convert the @Output() properties to their output() equivalents.

  • Imports in the file of components or directives, at TypeScript module level, are updated as well.

  • For projects with API calls such as event.next(), which are not recommended, they are migrated to event.emit() and removes event.complete() calls.

Conclusion

As the Angular framework continues to evolve, it is highly recommended to start adopting the Signal-based architecture which gives you improved change detection, moving away from the monkey patching that was witnessed when working ZoneJS-based Angular applications. With Zoneless Angular applications now being the default past Angular v21, Signal-based architecture is the now go-to for an ideal Angular application and improved Developer Experience.

Top comments (0)