5

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.

JNK
  • 796
  • 6
  • 12

2 Answers2

6

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);
Can Nguyen
  • 1,470
  • 10
  • 11
2

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.

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thank you for the answer. It worked fine for only two pages, but the second call could have the hasMore flag set again. I guess i need a recursive call like this: http://pastebin.com/JnDu1uJz Also I want to show the results that are already there immediately and add the others as they come. I used startWith and scan for that. Is that correct? – JNK Jul 11 '16 at 16:04