I am trying to utilse some of Angular’s new reactivity with Signal. I am following this workflow, and converting one of my observables into a signal, this is then being read and displayed on my screen.
https://angular.dev/guide/signals/rxjs-interop#tosignal
Working Example
** T.S **
response_obs$ =
this.apiService.getResponse();
response_signal: Signal<any> = toSignal(response_obs$, {initialValue: 0})
** HTML **
<div *ngIf="response_signal()">
<div class="item" *ngFor="let item of response_signal().items ">
<label>{{ item.name }}</label>
<small>{{ item.website }}</small>
</div>
</div>
This all works and prints correctly. We have replaced the async pipe by using the toSignal() function.
What I am trying to achevive next is reacitvity. When I post to this API in aother part of the application the observable will have new data to emit, if I refresh the webpage this appears but the change is not registered.
The update to the observable can be triggered via and Event Emitter, is there tooling within Angular Signals workflow that can be used here?
2
Answers
Angular’s Signals library, introduced in Angular 13, provides a way to work with reactive data in a more concise and efficient manner. However, for your specific use case of updating the Signal when an observable changes due to an event emitter, you can achieve reactivity using Angular Signals. To make your Signal react to changes in the underlying observable triggered by an event emitter, you can use the merge operator from RxJS to combine the original observable with an observable that represents the event emitter. Here’s how you can do it: 1. Define your
response_obs$
observable as you did before:Create an observable for the event emitter. You can do this by creating a subject and emitting values when the event occurs:
private updateEventEmitter = new Subject();
// Method to trigger the update event
// Subscribe to the event emitter observable
Combine your original response_obs$ observable and the updateEvent$ observable using the merge operator. This will create a new observable that emits whenever either the original observable emits data or the event emitter emits a value.
combinedObs$ = merge(
this.response_obs$,
this.updateEvent$.pipe(switchMap(() => this.apiService.getResponse()))
);
Convert the
combinedObs$
observable into a Signal, just like you did before:response_signal: Signal = toSignal(this.combinedObs$, { initialValue: 0 });
Now, whenever you call
triggerUpdate()
, it will trigger the event emitter, which in turn will update thecombinedObs$
observable with new data from this.apiService.getResponse(). The Signal will react to changes in combinedObs$ and display the updated data in your HTML template. In your HTML template, you don’t need to make any changes because you’re already using theresponse_signal()
function to display the data, and it will automatically react to changes in the Signal.Create an Observable to call
getResponse()
every time a response changes. Initiating it with a BehaviorSubject makes the most sense so that it will immediately start an observable stream. The create a stream inside oftoSignal()
(you don’t even have to assign it to a variable) that chains emissions to calls to the service.TS
HTML