Skip to content
beginner Phase 3 · Components, Templates, and Lifecycle

Emitting Events with @Output

Notify parent components of user actions through typed events.

35m
0 problems
Topic Progress 0%

Emitting Events to Parent Components

The @Output decorator allows a child component to notify its parent of user actions or state changes by emitting events.

Basic Usage

// child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<button (click)="onSelect()">Select</button>`,
})
export class ChildComponent {
  @Output() selected = new EventEmitter<string>();

  onSelect(): void {
    this.selected.emit('user-123');
  }
}
// parent.component.ts
@Component({
  selector: 'app-parent',
  template: `
    <app-child (selected)="onSelected($event)"></app-child>
    <p>Selected: {{ selectedId }}</p>
  `,
})
export class ParentComponent {
  selectedId = '';

  onSelected(id: string): void {
    this.selectedId = id;
  }
}

EventEmitter is an Observable

EventEmitter extends Subject, so you can use RxJS operators on it:

@Output() search = new EventEmitter<string>();

ngOnInit(): void {
  this.search.pipe(
    debounceTime(300),
    distinctUntilChanged()
  ).subscribe(query => {
    // perform search
  });
}

Output Aliases

@Output('itemSelected') selected = new EventEmitter<Item>();
<app-child (itemSelected)="onSelect($event)"></app-child>

Emitting Multiple Values

@Output() action = new EventEmitter<{ type: string; payload: any }>();

this.action.emit({ type: 'delete', payload: { id: 123 } });

Signal-Based Outputs (Modern Angular)

Angular 17+ provides output() as a signal-based alternative to @Output.

output() Function

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

@Component({
  selector: 'app-child',
  template: `<button (click)="selected.emit('user-123')">Select</button>`,
})
export class ChildComponent {
  selected = output<string>();
}

@Output vs output()

Feature @Output output()
Syntax Decorator + EventEmitter Function call
Type safety EventEmitter output()
Alias @Output('alias') output({ alias: 'alias' })
Operators Yes (EventEmitter extends Subject) No (use pipe in parent)

model() for Two-Way Binding

model() creates a signal that supports two-way binding with [(syntax)]:

@Component({
  selector: 'app-counter',
  template: `
    <button (click)="count.set(count() - 1)">-</button>
    <span>{{ count() }}</span>
    <button (click)="count.set(count() + 1)">+</button>
  `,
})
export class CounterComponent {
  count = model<number>(0);
}
<app-counter [(count)]="parentCount"></app-counter>

This is equivalent to:

<app-counter [count]="parentCount" (countChange)="parentCount = $event"></app-counter>

Complete Parent-Child Communication Example

// child.component.ts
@Component({
  selector: 'app-todo-item',
  template: `
    <div [class.done]="item().done">
      <input type="checkbox" [checked]="item().done" (change)="toggle.emit()">
      <span>{{ item().text }}</span>
      <button (click)="remove.emit()">Delete</button>
    </div>
  `,
})
export class TodoItemComponent {
  item = input.required<{ text: string; done: boolean }>();
  toggle = output<void>();
  remove = output<void>();
}
// parent.component.ts
@Component({
  selector: 'app-todo-list',
  template: `
    <app-todo-item
      *ngFor="let todo of todos"
      [item]="todo"
      (toggle)="toggleTodo(todo)"
      (remove)="removeTodo(todo)">
    </app-todo-item>
  `,
})
export class TodoListComponent {
  todos = [
    { text: 'Learn Angular', done: false },
    { text: 'Build app', done: false },
  ];

  toggleTodo(todo: any): void {
    todo.done = !todo.done;
  }

  removeTodo(todo: any): void {
    this.todos = this.todos.filter(t => t !== todo);
  }
}

Quiz

1. What class does @Output use to emit events?

Question 1 options

2. What is the signal-based alternative to @Output?

Question 2 options

3. What does model() create?

Question 3 options

Flashcards

Question

How does a child component notify its parent?

Answer

@Output() with EventEmitter, or output() signal. Parent listens with (event) binding.

Question

What is EventEmitter?

Answer

A class that extends Subject. The child calls .emit(value) and subscribers receive the value.

Question

What does model() do?

Answer

Creates a two-way bindable signal. Use [(property)] syntax in the parent template.

Revision Notes

Key Takeaways

  • 1. @Output + EventEmitter enables child-to-parent communication
  • 2. output() is the modern signal-based alternative
  • 3. model() creates two-way bindable signals
  • 4. EventEmitter extends Subject, so RxJS operators work on it

Interview Tips

  • • Explain the data flow: @Input down, @Output up
  • • Be ready to describe model() for two-way binding
  • • Mention that EventEmitter is an Observable under the hood

Cheat Sheet

@Output Cheat Sheet

Decorator syntax:

@Output() selected = new EventEmitter<string>();
this.selected.emit('value');

Signal syntax:

selected = output<string>();
this.selected.emit('value');

Two-way binding:

count = model<number>(0);
<app-counter [(count)]="parentCount"></app-counter>

Parent template:

<app-child (selected)="onSelected($event)"></app-child>

Continue Learning