RxJS library and Observables explained
The Observable pattern provides the new way used in angular to deliver values between a publisher and its subscriber, and angular takes advantage of the RxJS library to exploit it.
Observable
Multiple Push collection. Register all the values produced. To access to this value, it's necessary to subscribe to it. That's why it exposes a method subscribe
to see these values.
Observer
Handler for receiving observable notifications. It defines a next
method that handles each delivered value. Can define an error
method and a complete
method.
Subscribe
The subscribe method is necessary to access to an observable values. To subscribe to an observable, an easy way is to create a subscription, subscribe, use the values, and remember to unsubscribe when the component is destroyed.
private subscription: Subscription = Subscription.EMPTY;
ngOnInit() {
this._subscription = this.observable$.subscribe((res) =>{
this.doSomething(res);
this.cd.markForCheck();
} );
}
ngOnDestroy() {
this._subscription.unsubscribe();
}
In this case, if the DetectionStrategy
is onPush
, the component inside the subscribe method might have to ask to update for changes, with the this.cd.markForCheck()
instruction.
In the template, the pipe async
subscribe and unsubscribe automatically, passing to the children the observed values.
This is a good article about the differences between subscribe and async pipe: https://medium.com/angular-in-depth/angular-question-rxjs-subscribe-vs-async-pipe-in-component-templates-c956c8c0c794
Operators
Operators transform the values emitted by an observable. The operators can be of different types, and usually are chained inside a pipe
operator. There are a lot of them, below you can find some useful use cases.
shareReplay
When an observable has multiple subscriptions, use shareReplay
to evaluate the observable just once and share it's value. For example when there are more then one | async
in the template for the same observable.
if-then-else
Simulate Often there is no need to use RxJS operators for the if-then-else
behavior, because this construct can be used inside a switchMap
or concatMap
block.
this.filteredOptions$ = this._inputValue$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((term) => {
if (term && term.length > 2) {
return this._customerService.searchCustomersGet("", term || "");
} else {
return of({ items: [] });
}
})
);
if this is not possible, use iif
, that subscribes to first or second observable based on a condition.
Subject
Subjects is both a observable (you can subscribe to it) and an observer (it has next, error and complete methods). Subject is the minimal version, no state, all that gets pushed with next is lost if no subscribers. They are used in a multicasting scenario.
BehaviorSubject
Behaviour subject has state, the last emitted value or the one used in the constructor. Any new subscriber, will receive that stored value when it subscribes and the all the future emitted values.
ReplaySubject
ReplaySubject is a Subject that stores the number of previous emitted values indicated in the constructor. When it receives a new subscriber, it emits the last n values (if they exist) and the all the new values.
Add subscriptions
The add
method is very useful to put together subscriptions, maybe related. In this way the unsubscribe()
method unsubscribes from all of them.
Be careful to not reassign the subscription, or it will be replaced without unsubscribe it.
To use it, first create the subscription:
this._mySubscription = new Subscription();
And then add to that sink using the add method:
this._mySubscription.add((this.form.get(
'controlName',
) as FormControl).valueChanges.subscribe(($val) =>
consoleLog($val)
));
Remember to write the unsubscribe method in the ngOnDestroy
:
this._mySubscriptionKeyname.unsubscribe();