Dustin Malone
Dustin Malone

Reputation: 372

What is the proper method for using the output of one observable as the input to another in angular

I need to call a service with an async (http) return, and use it's output as an additional input to a service method (which returns an observable). What's the best way to do this in Angular 4+?

I have tried 'chaining' the results in the "subscribe" method of the first service, but doing this my service always returns 'null'.

public secondServiceCall: Observable<object> {
   this.firstService.next().subscribe(result=> {
      item.number = result;

      return this.httpService.post<object>('/new', item);
   });
}

I expected that the function wouldn't return until the subscription for the firstService was completed (async like), but this didn't happen - and instead I got 'null' in my calling function.

I have also tried to use the firstService call as an observable - this returns the second observable correctly, but never waits for the "then" function to execute before firing the second observable.

this.firstService.next().toPromise().then(result=> {
  item.number = result;
});

return return this.httpService.post<object>('/new', item);

Upvotes: 1

Views: 2667

Answers (2)

Yevhenii Dovhaniuk
Yevhenii Dovhaniuk

Reputation: 1103

In your case it's not important which combining operator to use: flatMap, concatMap or switchMap; they will behave the same because Angular's http emits a value only once and immediately completes.

Usually you would like to prefer concatMap more because this operator respects the order of emissions (meaning that if you have some delayed calls in your Observables they will be executed one after another, while flatMap and switchMap can lead to uncertain results, more details here https://www.baeldung.com/rxjava-flatmap-switchmap).


TLDR; Use concatMap

this.http.get('one').pipe(
  concatMap(result => this.http.get('two'))
)

Upvotes: 5

Phix
Phix

Reputation: 9880

Import the switchMap operator:

import { switchMap } from 'rxjs/operators';

Whatever the method in firstService that returns an observable of whatever item is, wrap that as such:

public secondServiceCall: Observable<object> {
   return this.firstService.someMethod().pipe(
      switchMap(item => {
         return this.httpService.post<object>('/new', item);
      })
   ) // result of your HTTP call based on item from firstService is now available when you subscribe
}

What this does is execute whatever your firstService method is which returns an Observable<item>, then switches over to the httpService.post call, which is supplied the result of the firstService method as the first argument.

Edit: Thanks JB Nizet, combined multiple iterations of the answer :/

Upvotes: 7

Related Questions