ebakunin
ebakunin

Reputation: 3801

How do I switch between two Observables in order and have the subscription fire twice?

I am using RxJS. I have two Observables (API calls) that return a different amount of information for the same array. I want to switch between the Observables and have the subscription recognize both results, i.e. fire each time a value is returned.

Here's an example using Typescript (this does not work):

let foo = [];
const callOne$ = this.service.getSomeData$; // this should take 0.5 seconds
const callTwo$ = this.service.getAllTheData$; // this should take 6 seconds

callOne$.pipe(
    switchMap(data => data.length > 0 ? callTwo$ : of(data)
).subscribe(data => {
    console.log(data); // this fires once but I want it to fire twice
    foo = data;
});

The above example retrieves callOne$, then retrieves callTwo$, and then gives me the result. Instead I want the results of both in order. How would I subscribe to the Observables so that the first result is received and then updated by the second call?

Upvotes: 0

Views: 477

Answers (2)

ebakunin
ebakunin

Reputation: 3801

I discovered the best result is to use concat(), which responds to Observable results in order.

In other words:

concat(callOne$, callTwo$)
.subscribe(data => {
    console.log(data); // this will fire twice
    foo = data;
});

This code will return two results for data, updating the variable in the order of the concat() list.

Upvotes: 0

Picci
Picci

Reputation: 17762

The simplest way may be

merge(callOne$, callTwo$)
.subscribe(data => { 
    console.log(data); // this fires twice but results are not guaranteed to be ordered
    foo = data;
});

You can keep the order but have a single event emitted with something like this

forkJoin(callOne$, callTwo$)
.subscribe(([data1, data2]) => { // this fires once with both results ordered
     console.log(data1); 
     console.log(data2);
     foo = data;
 });

If you want to have 2 separate notification maintaining the order, i.e. first the result of callOne$ and then the result of callTwo$, you may try to use the expand operator like this

callOne$.pipe(
  expand(val => callTwo$),
  take(2)  // to make sure you do not call callTwo$ infinitely
)
.subscribe(data => { 
  console.log(data); // this fires twice and the results are guaranteed to be ordered
  foo = data;
});

Looking at the fact that foo is an array, you may be inclined to the use of forkJoin, i.e. the second option.

You may find a more detailed explanation in this article.

Upvotes: 1

Related Questions