Tom
Tom

Reputation: 665

Angular4 returning Observable with nested Observables

I have a service that returns an Observable containing a collection of objects. The initial web call returns a collection, however within the collection of items, I need to make a supplementary call to retrieve some extra data. The result should be a new object which is generated using the two responses.

The code looks a bit like this:

let result: Array<InvitationModel> = new Array<InvitationModel>();

this.apiService.getInvitations().map((invitations : Array<InvitationResponse>) => {
     invitations.forEach(inv => {
      this.apiService.getInvitationData(inv).map((data: DataResponse) => {
      result.push(new InvitationModel(inv, data));        
    });
});

return result;

This doesn't work, which I understand, but I'm not sure of the correct way to write it so that I can only return result once the loop has completed.

Any advice would be appreciated.

Upvotes: 1

Views: 800

Answers (1)

Nicolas Gehlert
Nicolas Gehlert

Reputation: 3253

What you are looking for is the Rxjs.Observable.switchMap metho (https://www.learnrxjs.io/operators/transformation/switchmap.html) With this method you will wait until all the observables in the switchmap block are resolved (you basically switch to a new observable). Also the way with the result array won't work since the observable part is executed async, that means you should return an observable from your function and subscribe on the outside to retrieve the data

Your example could look something like this:

return this.apiService.getInvitations().switchMap((invitations: Array<InvitationResponse>) => {

    let result: Array<InvitationModel> = new Array<InvitationModel>();
    return Observable.forkJoin(...invitations.map(inv => {
        this.apiService.getInvitationData(inv).map((data: DataResponse) => {
            result.push(new InvitationModel(inv, data));
        });
    })).map(() => {
        return result;
    });
});

Quick explanation:

As I said above with the .switchMap you are waiting until your child observables are resolved

With invitations.map(inv => {you create an array with observables for your child operation.

With Observable.forkJoin( you combine all the observables from the array to a single one to wait for.

Upvotes: 4

Related Questions