Gaurav Mukherjee
Gaurav Mukherjee

Reputation: 6335

Concat paginated response using Rxjs in angular2

I am calling an external API from an angular2 app, which provides data in paginated form. The response looks like this

{
   next: "next_url",
   results: []
}

Can I use Rxjs or inbuilt Http class of Angular2, which returns an observable, to concat the results from next url, till

{
   next: null,
   results: []
}

I feel I need to user concatMap operator, but I have not figured out the syntax as I am new to Reactive Extentions.

Upvotes: 3

Views: 3855

Answers (2)

Gaurav Mukherjee
Gaurav Mukherjee

Reputation: 6335

Just of sake of an alternative solution this one also works

getAllResults(startIdx = 0) {
  return this.getData(startIdx)
    .expand(data => {
      return data.next ? this.getData(data.next) : Observable.empty()
    }).scan((acc, data) => {
      return [...acc, ...data.results]
    }, []);

}

expand operator recursively call the inner observable. Without scan operator, it would keep emitting data of each page. Use scan to reduce the data of each page into single array of results.

Note: This is not exactly the solution I was looking for. Because it emits each page results as array, and not just the final array. But was interesting to discover these useful operators.

http://plnkr.co/edit/vrZEywkeys6sa5Nsccbg?p=preview

Upvotes: 4

Lodewijk Bogaards
Lodewijk Bogaards

Reputation: 19987

Here is how I would do it:

import {Component} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/Rx';

@Component({
  selector: 'my-app',
  template: `<h2>Results: {{out | async | json}}</h2>`,
})
export class App {
  constructor() { 
    this.out = this.getAllResults();
  }

  getAllResults(startIdx = 0) {
    return this.getData(startIdx)
      .concatMap(data => {
        if (data.next) {
          return this.getAllResults(data.next)
            .map(resultsToJoin => [...data.results, ...resultsToJoin]);
        } else {
          return Observable.of(data.results);
        }
      });
  }

  // pretend this is our http call 
  getData(idx : number) {
    const data = [{
        next: 1,
        results: [1, 2]
      }, {
        next: 2,
        results: [3, 4]
      }, {
        next: null,
        results: [5, 6]
    }];

    return Observable.of(data[idx]);
  } 
}

http://plnkr.co/edit/7r4TaW

Upvotes: 5

Related Questions