Reputation: 6335
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
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
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]);
}
}
Upvotes: 5