← Back to Chapters

Reusable Components

? Reusable Components

? Quick Overview

In Angular, reusable child components can receive data from a parent using @Input and send events back using @Output with EventEmitter. This pattern helps you create clean, modular, and maintainable UIs where logic is shared across multiple places.

? Key Concepts

  • @Input() – Passes data from a parent component to a child component.
  • @Output() – Sends events from a child component back to the parent.
  • EventEmitter – Used with @Output to emit custom events.
  • Reusable child component – Encapsulates UI + logic so it can be used in many places.
  • *ngFor – Renders multiple instances of the child component for lists.

? Syntax & Theory

Child ➜ Receives Data

A child component marks a property with @Input() to receive data:

  • The parent binds a value using [propertyName]="value".
  • The child can display or process that value in its template.

Child ➜ Emits Events

A child component marks an EventEmitter with @Output():

  • The child calls this.eventName.emit(data) to notify the parent.
  • The parent listens using (eventName)="handler($event)".

? Creating a Reusable Child Component

The child component shows a single product and emits an event when the user clicks Buy.

? View Code Example (child.component.ts)
// child.component.ts - reusable product item component
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
    <p>Item: {{ item.name }} - Price: {{ item.price }}</p>
    <button (click)="buyItem()">Buy</button>
  `
})
export class ChildComponent {
  @Input() item: any; // Data received from the parent component
  @Output() purchase = new EventEmitter<any>(); // Event sent back to the parent

  buyItem() {
    this.purchase.emit(this.item); // Emit selected item when Buy is clicked
  }
}

? Using the Reusable Component in the Parent

The parent component passes a list of products to multiple child components and reacts to the purchase event.

? View Code Example (parent.component.ts)
// parent.component.ts - using the reusable child component
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <h2>Available Products</h2>
    <app-child
      *ngFor="let product of products"
      [item]="product"
      (purchase)="handlePurchase($event)">
    </app-child>
  `
})
export class ParentComponent {
  products = [
    { name: 'Laptop', price: 1000 },
    { name: 'Phone', price: 500 }
  ]; // Data source passed into child components

  handlePurchase(product: any) {
    console.log('Purchased:', product); // Handle the event from the child
  }
}

? Live Output & Explanation

? What Happens at Runtime?

  1. Parent prepares data – The products array holds a list of items.
  2. *ngFor creates children – For each product, Angular creates an <app-child> instance and passes [item]="product".
  3. Child shows product info – The child template renders the product name and price.
  4. User clicks Buy – The buyItem() method runs in the child component.
  5. Event is emitted – The child calls purchase.emit(this.item).
  6. Parent handles event – The parent’s handlePurchase($event) receives the selected product and logs it or updates state (e.g., add to cart).

This pattern keeps display logic inside the child and business logic inside the parent.

? Tips & Best Practices

  • Keep components small and focused. One component should represent one clear piece of UI.
  • Type your inputs and outputs. For example, @Input() item!: Product; and @Output() purchase = new EventEmitter<Product>(); for better type safety.
  • Do not mutate @Input data directly. Instead, emit events and let the parent update state.
  • Reuse components with *ngFor. Perfect for lists such as products, users, or tasks.
  • Name outputs clearly. Use names like selected, changed, purchase to describe the event meaningfully.

? Try It Yourself

  • Create a reusable UserCardComponent that accepts a user object via @Input() and displays their name and email.
  • Use *ngFor in a parent component to render a list of user cards from an array of users.
  • Add an @Output() in UserCardComponent that emits when the card is clicked, and handle it in the parent to maintain a “selected users” list.
  • Log the emitted data in the console and then extend it to update the UI (e.g., show selected users below).