Dev Notes Blog

Exploring the New output() Function in Angular

6th July 2024
Angular
angular
Last updated:6th September 2025
4 Minutes
709 Words

Angular has introduced a new way to define output events in components with the output() function. This addition provides a modern and concise alternative to the traditional @Output decorator.

new output() API

By replacing @Output with output(), you’ll find that your application continues to function seamlessly. This new approach maintains compatibility and offers some additional features.

child-component.ts
1
import { Component, output, OutputEmitterRef, Output } from '@angular/core';
2
3
@Component({
4
selector: 'child-component',
5
standalone: true,
6
template: `<button (click)="emitClick($event)">Click here</button>`,
7
})
8
export class ChildComponent {
9
@Output() deletedClick = new EventEmitter<MouseEvent>();
10
deletedClick = output<MouseEvent>();
11
@Output('deletedElement') elementDeleted = new EventEmitter<MouseEvent>(); //-> with alias
12
elementDeleted = output<MouseEvent>({ alias: 'deletedElement' }); //-> with alias
13
emitClick(event: MouseEvent): void {
14
this.deletedClick.emit(event);
15
this.elementDeleted.emit(event);
2 collapsed lines
16
}
17
}
1
<app-component (deletedClick)="fn($event)" (deletedElement)="fn($event)" />

Key Features

  1. Simplicity: The output() function simplifies the syntax, making the code cleaner and easier to read.
  2. Aliases: Similar to @Output, you can still define aliases for your outputs. While it’s not recommended to frequently use aliases, it’s important to know that this capability is retained with output().
  3. Backward Compatibility: Switching to output() won’t break your existing functionality. Your components will behave just as they did with @Output.

Comparing OutputEmitterRef with EventEmitter

With the introduction of output(), Angular also introduces OutputEmitterRef. Let’s compare it with the traditional EventEmitter.

child-component.ts
1
@Output() deletedClick: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
2
deletedClick: OutputEmitterRef<MouseEvent> = output<MouseEvent>();

EventEmitter

  1. Purpose: EventEmitter is used to create events that can be emitted and subscribed to. It extends Subject and provides methods to emit events.
  2. Methods: .emit(value: T) to emit a value, .subscribe(handler: Function) to subscribe to the event.

OutputEmitterRef

  1. Purpose: OutputEmitterRef is an internal type returned by output(), simplifying the creation and management of output events.
  2. Methods: Similar to EventEmitter, it includes .emit(value: T) to emit a value and .subscribe(handler: Function) to handle subscriptions.

Subscribing to Outputs Programmatically

Subscribing to outputs programmatically remains straightforward with the new output() function. Here’s how you can do it:

parent-component.ts
1
import { Component, Signal, effect, viewChild, ViewChild } from '@angular/core';
2
import { ChildComponent } from './child-component';
3
4
@Component({
5
selector: 'parent-component',
6
standalone: true,
7
imports: [ChildComponent],
8
template: `<child-component />`,
9
})
10
export class ParentComponent implements AfterViewInit {
11
export class ParentComponent {
12
@ViewChild(ChildComponent) myComponentRef!: ChildComponent;
13
myComponentRef: Signal<ChildComponent> = viewChild.required(ChildComponent);
14
15
constructor() {
13 collapsed lines
16
effect(() => {
17
this.myComponentRef().deletedClick.subscribe((event: MouseEvent) => {
18
console.log('Event received:', event);
19
});
20
});
21
}
22
23
ngAfterViewInit() {
24
this.myComponentRef.deletedClick.subscribe((event: MouseEvent) => {
25
console.log('Event received: ', event);
26
});
27
}
28
}

it automatically completes when the component or directive is destroyed.

New RxJS-Interop Functions

Two additional functions have been introduced in the RxJs Interop package to further enhance the capabilities of this new API.

outputFromObservable()

With the brand new outputFromObservable() function, you can now create an output directly from an Observable.

timer.component.ts
1
import { Component, OutputRef } from '@angular/core';
2
import { outputFromObservable } from '@angular/core/rxjs-interop';
3
import { interval } from 'rxjs';
4
5
@Component({
6
selector: 'timer-component',
7
standalone: true,
8
template: `...`,
9
})
10
export class TimerComponent {
11
timer: OutputRef<number> = outputFromObservable(interval(1000));
12
timerAlias = outputFromObservable(interval(1000), { alias: 'timerChange' });
13
}

Both the Observable and the output are automatically completed when the component or directive is destroyed.

If an error occurs, the Observable is interrupted, causing the output to stop emitting and the error to propagate (unless it is caught).

outputToObservable()

With the brand new outputToObservable() function, you can now transform an output directly to an Observable.

parent-component.ts
1
import { Component, Signal, effect, viewChild, ViewChild } from '@angular/core';
2
import { outputToObservable } from '@angular/core/rxjs-interop';
3
import { ChildComponent } from './child-component';
4
5
@Component({
6
selector: 'parent-component',
7
standalone: true,
8
imports: [ChildComponent],
9
template: `<child-component />`,
10
})
11
export class ParentComponent {
12
myComponentRef: Signal<ChildComponent> = viewChild.required(ChildComponent);
13
14
constructor() {
15
effect(() => {
6 collapsed lines
16
outputToObservable(this.myComponentRef().elementDeleted).subscribe((event: MouseEvent) => {
17
console.log('Observable:', event);
18
});
19
});
20
}
21
}

Again, both the Observable and the output are automatically completed when the component or directive is destroyed.

Furthermore, due to the absence of errors in the outputs, the resulting Observable never emits error notifications.

Acknowledgment

This post draws inspiration and references from source post, providing valuable insights into Angular’s new output() function and related concepts. Special thanks to the original author for their contributions to the Angular community.

Source Code

You can find the source code for this post on GitHub, which includes examples and additional details discussed here.

Conclusion

The introduction of the output() function, OutputEmitterRef, and new RxJS interop functions in Angular provides a more streamlined way to handle output events and integrate reactive programming.

Article title:Exploring the New output() Function in Angular
Article author:Andrés Arias
Release time:6th July 2024