Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 Observable - Await multiple function calls before proceeding

I am trying to improve my knowledge of Angular2 by migrating an application currently written in Angular1/AngularJS.

One feature in particular has me stumped. I am trying to replicate a feature where a calling function waits to proceed until the function it is calling has completed a loop of promises. In AngularJS, the function I am calling looks basically like this:

this.processStuff = function( inputarray, parentnodeid ) {
    var promises = [];
    var _self = this;
    angular.forEach( inputarray , function( nodeid ) {

        switch ( parentnodeid )
        {
            case ‘AAA’ : var component = _self.doMoreStuff( nodeid, parentnodeid ); break;
            case ‘BBB’ : var component = _self.doMoreStuff( nodeid, parentnodeid ); break;
            case ‘CCC’ : var component = _self.doMoreStuff( nodeid, parentnodeid ); break;
            default    : var component = null;
        }
        promises.push( component );
    });
    return $q.all(promises);
}; 

It contains a forEach loop that calls another function (doMoreStuff) that also returns a promise, and it stores all those returned promises in an array.

With AngularJS, when I call processStuff in another function, I could count on the system waiting until processStuff completed before entering into the code in the then block:

service.processStuff( arraying, parentidarg )
       .then(function( data ) {
              ... 

The caller of processStuff waits for all doMoreStuff invocations to complete until the caller of processStuff enters into its then block.

I am unsure of how to achieve this with Angular2 and Observables. I can see from these posts that to mimic promises, Observables basically just use subscribe() instead of then():

Angular 1.x $q to Angular 2.0 beta

But how do I await all invocations in the forEach loop to complete before my application can proceed?

like image 360
Benjamin McFerren Avatar asked Feb 23 '16 01:02

Benjamin McFerren


2 Answers

I have been doing this with forkJoin

import {Observable} from 'rxjs/Observable'; import 'rxjs/add/observable/forkJoin';  Observable.forkJoin(   this.http.get('./friends.json').map((res: Response) => res.json()),   this.http.get('./customer.json').map((res: Response) => res.json()) ) .subscribe(res => this.combined = {friends: res[0].friends, customer: res[1]}); 

Some more info here: http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http

like image 113
TGH Avatar answered Sep 20 '22 11:09

TGH


In RxJS v6 and later you can do this more eloquently with zip.

    import { zip } from 'rxjs';

    const promise1 = yourSvc.get(yourFavoriteAPI.endpoint1);
    const promise2 = yourSvc.get(yourFavoriteAPI.endpoint2);

    const promises = zip(promise1, promise2);

    promises.subscribe(([data1, data2]) => {
      console.log(data1);
      console.log(data2);
    });

While the result is the same, I find zip preferable to forkJoin since zip is more universal and can handle new values from the observables.

Details from the rxjs documentation:

The zip operator will subscribe to all inner observables, waiting for each to emit a value. Once this occurs, all values with the corresponding index will be emitted. This will continue until at least one inner observable completes.

like image 22
Tony Brasunas Avatar answered Sep 20 '22 11:09

Tony Brasunas