In this post we show some ways to combine observables. I made a stackblitz example project to give you a working example. The RxJS part of the project will be discussed in this post.

Disabled while loading

We start out with 2 buttons that call a mock service. Clicking Option 1 results in a wait for 2 seconds and then a value. Clicking Option 2 emits an error after 2 seconds. The functionality we want is that clicking either button, disables both buttons until the call returns.

First of all we want an operator that tells us when an observable is pending. We will define the operator is a separate file.

export function isPending<T>(): OperatorFunction<T, boolean> {
    return (input$: Observable<T>) => concat(
        of(true),
        input$.pipe(mapTo(false), catchError(() => EMPTY)),
        of(false)
    ).pipe(distinctUntilChanged());
}

We see a concat that appends all containing observables. So we begin with a true, end with a false and in the middle map an emitted value to false with mapTo and map an emitted error to nothing (so we end with the false). In other words we begin with true and get a false on every value, error or complete. With distinctUntilChanged we only emit something if we get a distinct value of the previous value.

Now we define the relevant observables in the ngOnInit method. These are just the definitions, nothing is happening yet. This happens when we subscribe to these observables in the template.

<button [disabled]="awaitingResult$ | async">Option 1</button>

The desired functionality is given by combining the outcomes of the 2 options, which are emitted on the ReplaySubject‘s corresponding to these options.

this.awaitingResult$ = merge(
    this.firstOptionSubject,
    this.secondOptionSubject
).pipe(
    switchMap((result$) => result$.pipe(isPending()))
);

Here we see that we merge both subjects and switchMap with the isPending helper function. So when one of the subjects emit something we switch to an observable with the isPending pipe. This emits a false if the service call returns.

Show message on error

Next we want to show an error message when one of the service calls fails. We initialise the following observable to say when the error should be shown.

this.secondApiCallFailed$ = this.secondOptionSubject.pipe(
    switchMap((result$) => result$.pipe(
        startWith(false),
        mapTo(false),
        catchError((error) => of(true))
    ))
);

When the second service call returns we switch to the inner observable we defined. We startWith a false so that the error message is not show without any interaction. Every value is converted to false with mapTo because no error was thrown in this situation. And any error will be caught by catchError and converted into true, showing the error message on the screen.

I hope these examples gave relatable use cases in which you can use all these RxJS operators and combine your observables.