IMPORTANT: The RxJS Interop package is available for developer preview. It's ready for you to try, but it might change before it is stable.
Angular's @angular/core/rxjs-interop package provides useful utilities to integrate Angular Signals with RxJS Observables.
toSignal
Use the toSignal function to create a signal which tracks the value of an Observable. It behaves similarly to the async pipe in templates, but is more flexible and can be used anywhere in an application.
import { Component } from '@angular/core';import { AsyncPipe } from '@angular/common';import { interval } from 'rxjs';import { toSignal } from '@angular/core/rxjs-interop';@Component({ template: `{{ counter() }}`,})export class Ticker { counterObservable = interval(1000); // Get a `Signal` representing the `counterObservable`'s value. counter = toSignal(this.counterObservable, {initialValue: 0});}
Like the async pipe, toSignal subscribes to the Observable immediately, which may trigger side effects. The subscription created by toSignal automatically unsubscribes from the given Observable when the component or service which calls toSignal is destroyed.
IMPORTANT: toSignal creates a subscription. You should avoid calling it repeatedly for the same Observable, and instead reuse the signal it returns.
Injection context
toSignal by default needs to run in an injection context, such as during construction of a component or service. If an injection context is not available, you can manually specify the Injector to use instead.
Initial values
Observables may not produce a value synchronously on subscription, but signals always require a current value. There are several ways to deal with this "initial" value of toSignal signals.
The initialValue option
As in the example above, you can specify an initialValue option with the value the signal should return before the Observable emits for the first time.
undefined initial values
If you don't provide an initialValue, the resulting signal will return undefined until the Observable emits. This is similar to the async pipe's behavior of returning null.
The requireSync option
Some Observables are guaranteed to emit synchronously, such as BehaviorSubject. In those cases, you can specify the requireSync: true option.
When requiredSync is true, toSignal enforces that the Observable emits synchronously on subscription. This guarantees that the signal always has a value, and no undefined type or initial value is required.
manualCleanup
By default, toSignal automatically unsubscribes from the Observable when the component or service that creates it is destroyed.
To override this behavior, you can pass the manualCleanup option. You can use this setting for Observables that complete themselves naturally.
Error and Completion
If an Observable used in toSignal produces an error, that error is thrown when the signal is read.
If an Observable used in toSignal completes, the signal continues to return the most recently emitted value before completion.
toObservable
Use the toObservable utility to create an Observable which tracks the value of a signal. The signal's value is monitored with an effect which emits the value to the Observable when it changes.
import { Component, signal } from '@angular/core';@Component(...)export class SearchResults { query: Signal<string> = inject(QueryService).query; query$ = toObservable(this.query); results$ = this.query$.pipe( switchMap(query => this.http.get('/search?q=' + query )) );}
As the query signal changes, the query$ Observable emits the latest query and triggers a new HTTP request.
Injection context
toObservable by default needs to run in an injection context, such as during construction of a component or service. If an injection context is not available, you can manually specify the Injector to use instead.
Timing of toObservable
toObservable uses an effect to track the value of the signal in a ReplaySubject. On subscription, the first value (if available) may be emitted synchronously, and all subsequent values will be asynchronous.
Unlike Observables, signals never provide a synchronous notification of changes. Even if you update a signal's value multiple times, toObservable will only emit the value after the signal stabilizes.
const obs$ = toObservable(mySignal);obs$.subscribe(value => console.log(value));mySignal.set(1);mySignal.set(2);mySignal.set(3);
Here, only the last value (3) will be logged.
outputFromObservable
outputFromObservable(...) declares an Angular output that emits values based on an RxJS observable.
class MyDir { nameChange$ = new Observable<string>(/* ... */); nameChange = outputFromObservable(this.nameChange$); // OutputRef<string>}
See more details in the output() API guide.
outputToObservable
outputToObservable(...) converts an Angular output to an observable.
This allows you to integrate Angular outputs conveniently into RxJS streams.
outputToObservable(myComp.instance.onNameChange) .pipe(...) .subscribe(...)
See more details in the output() API guide.