6

Probably a basic question, but I have an Angular app that makes a backend service call to retrieve some data and then uses that data to make another backend service call.

The second service call is dependent on the first completing successfully, so I use the concatMap() function from RxJS.

However, my code below is only returning the data for the second service call. I need all the data returned from both service calls.

Have a feeling I'm messing up the .pipe call, but not making much progress. Thanks in advance.

getData(id: String): Observable<any[]> {
return this.http.get<any>(`${this.baseUrl}/path/${id}`).pipe(
  concatMap(
    evt =>
      <Observable<any[]>>(
        this.http.get<any[]>(
          `${this.baseUrl}/path/relatedby/${evt.child_id}`
        )
      )
  ),
  retry(3),
  catchError(this.handleError("getData", []))
);}
RookieMcRookie
  • 403
  • 2
  • 5
  • 7

3 Answers3

4

The pipe function combines the given functions(supplied as arguments) and executes them in series, and finally returns the FINAL OUTPUT after going through the stages. That's why you're getting the result from the second call only, because that was the last function in the pipe (last function which returned a value).

eg: lets check this out

const filterOutEvens = filter(x => x % 2)
const double = map(value => value * 2);
const sum = reduce((acc, next) => acc + next, 0);

Observable.range(0, 10).pipe(
  filterOutEvens, 
  double, 
  sum)
 .subscribe(console.log); // 50

here, from [1, 2, 3, 4, 5, 6 ,7, 8, 9,10], it first filters out even numbers, giving [1,3,5,7,9], which is passed to the next function (double), which doubles every element of the given array, giving [2,6,10,14,18], which is passed to the next function in pipe, which is sum (adds up the elements in the array). The sum function is the LAST function in the pipe, and returns 50, which is not only the return value of sum(), but also the whole pipe() as well.

example code taken from:https://blog.hackages.io/rxjs-5-5-piping-all-the-things-9d469d1b3f44

Edit
If u really want the data from both requests, you could pack the results of the first request in the result of second request using 'map' operator

 getData(id: String): Observable<any[]> {
  return this.http.get<any>(`${this.baseUrl}/path/${id}`).pipe(
 concatMap(
    evt =>
       <Observable<any[]>>(
          this.http.get<any[]>(
      `${this.baseUrl}/path/relatedby/${evt.child_id}`
        ).map(res =>( {"response1":evt, "response2":res}) )
  )
 ),
 retry(3),
 catchError(this.handleError("getData", []))
 );}
D.B.K
  • 410
  • 2
  • 15
  • Thanks for the brilliant explanation of pipes, cleared a lot of doubt for me! The map response worked perfectly for me, though I did have to rap it in another pipe. Update code below for anyone interested, thanks again for the speedy response, greatly appreciated. – RookieMcRookie Jul 17 '18 at 19:07
0

Thanks, that worked a treat and the explanation of pipes cleared a lot of questions I had. The map function worked perfectly, though I just had to rap it in another pipe. Updated code below, many thanks again for the help, greatly appreciated.

getData(id: String): Observable<any> {
return this.http.get<any>(`${this.baseUrl}/path/${id}`).pipe(
  concatMap(
    evt =>
      <Observable<any>>(
        this.http
          .get<any>(`${this.baseUrl}/path/relatedby/${evt.child_id}`)
          .pipe(
            map(resp => ({
              evtData: evt,
              childData: resp
            }))
          )
      )
  ),
  retry(3),
  catchError(this.handleError("getData", []))
 );
}
Salahuddin Ahmed
  • 4,854
  • 4
  • 14
  • 35
RookieMcRookie
  • 403
  • 2
  • 5
  • 7
0

I could be wrong here but double piping sounds unnecessary. Leveraging the fat arrow syntax brackets for implicit return I made this work.

this.$obs = this.route.params.pipe(
    concatMap((params: Params) => {
        console.log(params);
        return this.useParams(params.id)
    }),
    share() // irrelevant
);

Let me know if there are caveats with this over the other answers. #concatMapKindaRocks

Ben Racicot
  • 5,332
  • 12
  • 66
  • 130