7

I'm writing an application that will monitor the current build number of all of our applications across different servers. This is done by making an http request to a txt file in every application. I'm doing that using a foreach loop.

The issue I'm having is that I'm not sure how (using Observables) to know when all of the requests are finished.

As the requests come back, I add the response as a property of an array of objects. Then once I have all of the data, I bind it to the component's template, where it gets filtered by a Pipe. As such, I need to make sure I don't bind it until all of the data is finished coming down.

Here is how I'm getting the data:

this.apps.forEach(app => {
  app.Environments.forEach(env => {
    this._buildMonitorService.getBuilds(env.URL)
      .subscribe((data) => {     
        setupBuilds(this.apps,data.url,data._body);
      });                
  });
});

setupBuilds adds the response to my array of applications.

The thing I'm looking for is effectively a Promise.all where I'll bind this.builds to the data setup in setupBuilds but I don't know how to do that with rxjs observables

Marcus
  • 822
  • 1
  • 8
  • 27
Alex Kibler
  • 4,674
  • 9
  • 44
  • 74

1 Answers1

16

Observable.forkJoin is the equivalent to Promise.all but for observables.

Here is a sample:

Here is the way you could refactor your code:

var observables = [];
this.apps.forEach(app => {
  app.Environments.forEach(env => {
    observables.push(this._buildMonitorService.getBuilds(env.URL));
  });
});

Observable.forkJoin(observables).subscribe(
  (result) => {
    result.forEach((data) => {
      setupBuilds(this.apps,data.url,data._body);
    });
  }
);

This way you will be sure that all requests were executed when the callback registered in the subscribe method is called...

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • So, I tried setting this up (first my own way and then again with your edited code), and I'm getting `Observable_1.Observable.forkJoin is not a function` – Alex Kibler Mar 15 '16 at 15:01
  • I do think your answer will be what I'm looking for, but it's not quite working – Alex Kibler Mar 15 '16 at 15:02
  • You need to import the operator: `import 'rxjs/add/operator/forkJoin';` or import everything from rxjs `import 'rxjs/Rx';` – Thierry Templier Mar 15 '16 at 15:04
  • I already am with `import {Observable} from 'rxjs/Observable';` – Alex Kibler Mar 15 '16 at 15:05
  • Yes but it only import a minimal set of methods on the `Observable` class. Try this: `import {Observable} from 'rxjs/Rx';` to have all (or import the operators one by one)... – Thierry Templier Mar 15 '16 at 15:06
  • @ThierryTemplier for me was `import 'import 'rxjs/add/observable/forkJoin';` ..add/observable instead ...add/operator – William Ardila Jul 29 '17 at 18:34
  • @ThierryTemplier Hi , how can i check each response before push them into an observable ? because i need to know if response.toJson().Done is equal to true or not . If not , so we can push it into the observables[] . – peyman gilmour Sep 21 '17 at 08:12
  • What if I have different types of HTTP requests and they all need to be handled in a different way i.e., I want to keep their code in the individual subscribe methods but I still want to know when all the HTTP request observables have completed. I don't care about getting the last emitted values from each observable in the forkJoin subscribe array. I only want to know when all the observables have completed – Urooj Mar 07 '23 at 04:26