AtozEvo
AtozEvo

Reputation: 31

Whats the correct method to chain Observable<void> with typescript (Angular)?

I've been searching for the right/best/correct way to chain a few Observable methods. I've read on the using pipe() and map() and so on, but i'm not 100% i fully understand. The basis is i have a few actions to carry out, which some needs to be in sequence, and some dont. Below are the 4 methods i need to call.

createOrder(order:Order):Observable<void>{
        return new Observable((obs)=>
                //Do Something
                obs.complete();
        )
}

updateCurrentStock(order:Order):Observable<void>{
        return new Observable((obs)=>
                //Do Something
                obs.complete();
        )
}

updateSalesSummary(order:Order):Observable<void>{
        return new Observable((obs)=>
                //Do Something
                obs.complete();
        )
}
updateAnotherDocument(order:Order):Observable<void>{
        return new Observable((obs)=>
                //Do Something
                obs.complete();
        )
}

From this 4, the flow should be createOrder ->updateCurrentStock->updateSalesSummary, updateAnotherDocument. As of now, what i have is

var tasks = pipe(
    flatMap(e => this.createOrder(order)),
    flatMap(e => this.updateCurrentStock(order)),
    flatMap(e => forkJoin([this.updateSalesSummary(order),this.updateAnotherDocument(order)])),
  );
  of(undefined).pipe(tasks).subscribe({
    error: (err) => {
      console.log(err);
      obs.error(err);
    },
    complete: () => {
      console.log('completed');
      obs.complete();
    }
  });

It works, but i'm not sure if this is the right/cleanest way of doing it and if there is any possible issues in the future.

Upvotes: 2

Views: 1819

Answers (2)

adrisons
adrisons

Reputation: 3723

There are a lot of rxjs operators, I recommend you read https://www.learnrxjs.io/learn-rxjs.

When you have an observable that depends on other's value use switchMap

Example:

const userId$: Observable<number>;

function getUserData$(userId: number): Observable<Data> {
  // yourService.fetchUser(userId);
}

userId$.pipe(switchMap((userId: number) => getUserData$(userId)));

When you do not care about the order, you can use:

  • if you want to emit the last value when all observables complete: forkJoin
  • if you want to emit every value as any observable emits a value: combineLatest

Example:

const userId$: Observable<number>;

function getUserAge$(userId: number): Observable<number> {
  // ...
}
function getUserName$(userId: number): Observable<String> {
  // ...
}
userId$.pipe(
  switchMap((userId: number) =>
    forkJoin([getUserAge$(userId), getUserName$(userId)])
  )
);

In your case I think the order does not matter, as none of your observables needs data from the previous one. So I think you should use combineLatest. If the order of emission and subscription of inner observables is important, try concatMap.

Upvotes: 1

Mrk Sef
Mrk Sef

Reputation: 8032

Using concat

concat will subscribe to your streams in order (not starting the next until the previous one completes.

This should be roughly equivalent.

One difference here is that unlike mergeMap, you're not transforming the output of an api call, it still gets emitted. Since you're not doing anything with the next callback in your subscription, it'll still look similar in the case.

concat(
  this.createOrder(order),
  this.updateCurrentStock(order),
  forkJoin([
    this.updateSalesSummary(order),
    this.updateAnotherDocument(order)
  ])
).subscribe({
  error: concosle.log,
  complete: () => console.log('completed');
});

An Aside:

Here's how I would re-write your original code to be a bit easier to read.

this.createOrder(order).pipe(
  mergeMap(_ => this.updateCurrentStock(order)),
  mergeMap(_ => forkJoin([
    this.updateSalesSummary(order),
    this.updateAnotherDocument(order)
  ]),
).subscribe({
  error: (err) => {
    console.log(err);
    obs.error(err); // <-- What's obs here?
  },
  complete: () => {
    console.log('completed');
    obs.complete();
  }
});

Upvotes: 1

Related Questions