Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a second http call and use the result in same Observable

I am using angular 2 and it's http component.

I want to call a REST API that will return a list of Elements. The size of that list is limited to 100 entries. If there are more items a hasMore flag will be set in the response. You then have to call the API again with the parameter page=2. It would be nice to have one Observable, with both server responses. My code looks something like this:

call({page: 1})
  .map(res => res.json())
  .do((res) => {
    if(res.meta.hasMore){
      // do another request with page = 2
    }
  }
  .map(...)
  .subscribe(callback)

call is a function that will use the http module to make the request and return an Observable. Inside of the if statement I want to make another http request and put the result on the same Observable, so that the callback, registered with subscribe, will be called twice (one time for each response).

I am not really sure how to do it. I tried using flatMap to make the next request, but had no success.

like image 924
JNK Avatar asked Jul 11 '16 13:07

JNK


2 Answers

Recursion is exactly what the expand operator is for:

let callAndMap = (pageNo) => call({page: pageNo}).map(res => {page: pageNo, data: res.json()});  // map, and save the page number for recursion later.

callAndMap(1)
.expand(obj => (obj.data.meta.hasMore ? callAndMap(obj.page + 1) : Observable.empty()))
//.map(obj => obj.data)    // uncomment this line if you need to map back to original response json
.subscribe(callback);
like image 79
Can Nguyen Avatar answered Sep 20 '22 14:09

Can Nguyen


You could leverage the flatMap operator for this:

call({page: 1})
  .map(res => res.json())
 .flatMap((res) => {
   if(res.meta.hasMore){
     return Observable.forkJoin([
       Observable.of(res),
       call({page: 2}).map(res => res.json()
     ]);
   } else {
     return Observable.of(res);
   }
 })
 .map(data => {
   // if data is an array, it contains both responses of request
   // data[0] -> data for first page
   // data[1] -> data for second page

   // if data is an object, it contains the result of the first page
 })
 .subscribe(callback);

The last map operator is to format the data in both cases for the callback specified in the subscribe method.

like image 25
Thierry Templier Avatar answered Sep 21 '22 14:09

Thierry Templier