intermediate18 min

Inputs and Outputs: Parent-Child Communication

Passing data into a child component and emitting events back up to a parent.

What you'll learn

  • Declare an @Input() property to receive data from a parent component
  • Declare an @Output() EventEmitter to send data/events back to a parent
  • Explain the one-directional data flow this pattern encourages

Explanation

A child component receives data from its parent via an @Input() property: @Input() title: string = ""; -- the parent sets it via property binding when using the child: <app-card [title]="cardTitle"></app-card>.

A child sends data or events back up to its parent via an @Output() EventEmitter: @Output() selected = new EventEmitter<number>();, then calling this.selected.emit(this.id) inside the child fires the event, and the parent listens with event binding: <app-card (selected)="onCardSelected($event)"></app-card> -- $event inside the parent's template refers to whatever value the child's emit() call passed.

This @Input/@Output pattern encourages a clear, one-directional data flow: data flows down through inputs, events flow up through outputs -- rather than a child directly reaching up and mutating its parent's state, which would make data flow much harder to trace through a larger app.

Guided lab

Predict: An @Output EventEmitter's emitted value

AngularNot executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, predict what it does, then reveal the real expected output.

This models an @Output EventEmitter's behavior with a plain callback, since a live parent-child template can't render here. Predict what the parent's handler receives.

class CardComponent {
  id = 42;
  private listeners: ((id: number) => void)[] = [];

  onSelected(callback: (id: number) => void): void {
    this.listeners.push(callback);
  }

  select(): void {
    for (const listener of this.listeners) {
      listener(this.id);
    }
  }
}

const card = new CardComponent();
card.onSelected((id) => console.log("Parent received id:", id));
card.select();

Stuck? Get a hint.

Common mistakes

  • Trying to have a child component directly mutate a property on its parent, instead of emitting an @Output() event and letting the parent decide how to respond.
  • Forgetting to actually call .emit(value) inside the EventEmitter, then wondering why the parent's (event) handler never fires.
  • Mismatching the type parameter on EventEmitter<T> with what's actually passed to emit(), losing type safety on the parent's $event.

Knowledge check

Knowledge check

1. What decorator marks a property that receives data from a parent component?
2. What must a child component call to actually fire an @Output() event?
3. What data-flow direction does @Input/@Output encourage?

Takeaway

Pass data into a child with @Input(), and have the child notify its parent with an @Output() EventEmitter's .emit() call -- data down, events up.

Summary

@Input() properties receive data from a parent; @Output() EventEmitters, fired with .emit(), send events back up -- encouraging clear, one-directional data flow.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.