Angular2 Observable - Await multiple function calls before proceeding
Asked Answered
R

2

33

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?

Race answered 23/2, 2016 at 1:5 Comment(0)
A
73

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

Astrogate answered 23/2, 2016 at 1:7 Comment(6)
the argument for the forkJoin can be an array? Could you please show an example where you are iterating with a for loop to populate this "array". I am not certain if the loop is inside or outside the new Observable block and how to use observer.next(); and observer.complete();Race
see here for specific import instructions: #34581971Race
Yes, it can be an array: github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/…Welker
also: import 'rxjs/add/observable/forkJoin'Thornton
Why did the Rx team choose the name forkJoin? Why not call it something descriptive like with or when? forkJoin is not clear what it doesClave
you can look up the fork/join model.Monseigneur
S
4

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.

Sherbrooke answered 13/7, 2020 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.