How to await rxjs Observable without changing all the code to promises

Viewed 1611

Is it possible to await an rxjs observable without changing to Promises? I am doing 6 requests OnInit() however, some of the requests finish before another, the order matters. Is it possible to await an observable in typescrypt? All functions look the same, they just make a different request to the server. Thanks for the help :) Here's my code:

I managed to achieve it by chaining the request( calling next request after I get the response from the previous one, however, that solution was not efficient and looked ugly)

 ngOnInit() {
      this.userId = this.auth.getUserId();

      this.getTrendingRentals();
      this.getFollowingRentals();
      ...
      this.getLuxuryRentals();
      //console.log(this.totalRentals);
    }

    private getTrendingRentals() {
        const rentalObservable = this.rentalService.getRentals();
        //Subscribe to service observer
        rentalObservable.subscribe((rentals: Rental[]) => {
          this.trendingRentals = rentals;
          this.totalRentals.push(this.trendingRentals);
        }, (err) => {
        }, () => {
      });
    }


    public getLuxuryRentals(): Observable<any>{
      return this.http.get('/api/v1/rentals/luxury');
    }
2 Answers

you can use switchMap in the pipe to use the result of the first observable in the subsequent observable.

of("Hello").pipe(
            switchMap(result => of(result + ", World")),
            switchMap(result => of(result + "!")),
          )
          .subscribe(console.log);
// output: Hello, World!

but if you don't need the result of the previous observable and just want to trigger observables in a specific order, you can use concat which waits for every observable to complete before triggering the next observable:

concat(
  of(1).pipe(delay(2000)),
  of(2).pipe(delay(500)),
  of(3).pipe(delay(1000))
)
.subscribe(console.log);

// output: 1 2 3

Methods that are fetching data shouldn't return subscriptions but return observables,

private getTrendingRentals() {
    return this.rentalService.getRentals();
}

rxjs provides few functions to address this kind of problem. Take a look at functions: merge, mergeMap, switchMap, concatMap.

For example:

this.auth.getUserId().pipe(
      mergeMap(userId => this.getTrendingRentals()),
      mergeMap(trendingRentals => this.getFollowingRentals()),
      mergeMap(followingRentals => this.getFollowingRentals()),
      mergeMap(luxuryRentals => this.getLuxuryRentals())
).subscribe(...)

or

this.auth.getUserId().pipe(
      mergeMap(userId => this.getTrendingRentals()),
      mergeMap(trendingRentals => merge(this.getFollowingRentals(), this.getFollowingRentals(), this.getLuxuryRentals()))
).subscribe(...)

Dependence on your particular needs.

Update: @jcal solution with concat looks better :)

Related