BoJoe22
BoJoe22

Reputation: 95

Pass result of one RxJS observable into next sequential observable

I am trying to do a basic chaining of RxJS HTTP calls where the first call is going to pass the ID of an object that was created server-side into the second call. What I am observing with my implementation is that only the first call is made and the second chained call is never executed.

Below is roughly the code that I have.

First call:

createItem(itemData) {
  return this.http.post(createUrl, itemData)
    .map((res) => res.json())
    .catch(this.handleError);
}

Second call:

addFileToItem(id, file): Observable<any> {
  return this.http.post(secondUrl + id, file)
    .map((res) => log(res))
    .catch(this.handleError);
}

Function defined mapping one call into the other:

createAndUpload(itemData, file): Observable<any> {
  return createItem(itemData, file)
    .map((res) => {
      if (file) {
        return addFileToItem(res.id, file);
      }
    });
}

And finally, where the observable is executed through a subscribe():

someFunction(itemData, file) {
  createAndUpload(itemData, file)
    .subscribe(res => {
      log(res);
      //go do something else
    };
}

Upvotes: 3

Views: 2661

Answers (2)

martin
martin

Reputation: 96891

The problem is in createAndUpload where map just turns the result from the first call into an Observable but you never subscribe to it.

So simply said you just need to use mergeMap (or concatMap in this case it doesn't matter) instead of map. The mergeMap operator will subscribe to the inner Observable and emit its result:

createAndUpload(itemData, file): Observable<any> {
  return createItem(itemData, file)
    .mergeMap((res) => {
      if (file) {
        return addFileToItem(res.id, file);
      }
      return Observable.empty(); // you can't return `undefined` from the inner Observable
    });
}

Upvotes: 3

BoJoe22
BoJoe22

Reputation: 95

Apparently the map() function doesn't actually return anything, meaning that an Observable object is not returned. Instead, a transforming operator such as mergeMap is needed.

Here is the code that ended up working, also using the "newer" .pipe() operator. The only place the code needed to be changed was in the Observable function where I defined the combination of the two separate Observables. In order to access the mergeMap operator, don't forget to import it from rxjs/operators.

For a reason that I will eventually figure out, I couldn't access the mergeMap without the pipe...

createAndUpload(itemData, file): Observable<any> {
  return createItem(itemData, file)
    .pipe(
        mergeMap((res) => {
          if (file) {
            return addFileToItem(res.id, file);
          }
        })
     )
}

Upvotes: 1

Related Questions