Eggy
Eggy

Reputation: 4174

Fire callback after two separate successful http requests

Root component of my application on init call two asynchronous functions from my services to get data. I would like to know how to call a function after they are both completed. I am using angular 2.0.0-alpha.44 and typescript 1.7.3

import {Component, OnInit} from 'angular2/angular2';

import {ServiceA} from './services/A';
import {ServiceB} from './services/B';


@Component({
  selector: 'app',
  template: `<h1>Hello</h1>`
})
export class App {
  constructor(
    public serviceA: ServiceA,
    public serviceB: ServiceB
  ) { }

  onInit() {

    // How to run a callback, after 
    // both getDataA and getDataB are completed?
    // I am looing for something similar to jQuery $.when()
    this.serviceA.getDataA();
    this.serviceB.getDataB();
  }
}

serviceA.getDataA and serviceA.getDataB are simple http get functions:

// Part of serviceA
getDataA() {
  this.http.get('./some/data.json')
    .map(res => res.json())
    .subscribe(
      data => {
        // save res to variable
        this.data = data;
      },
      error => console.log(error),
      // The callback here will run after only one 
      // function is completed. Not what I am looking for.
      () => console.log('Completed')
    );
}

Upvotes: 4

Views: 1402

Answers (3)

Nypan
Nypan

Reputation: 7246

A simple still parallel solution would be something like:

let serviceStatus = { aDone: false, bDone: false };

 let getDataA = (callback: () => void) => {
     // do whatver.. 
     callback();
 }

 let getDataB = (callback: () => void) => {
     // do whatver.. 
     callback();
 }

 let bothDone = () => { console.log("A and B are done!");

 let checkServiceStatus = () => {

     if ((serviceStatus.aDone && serviceStatus.bDone) == true)
        bothDone();
 }

 getDataA(() => { 
     serviceStatus.aDone = true;
     checkServiceStatus(); 
});

getDataA(() => { 
     serviceStatus.bDone = true;
     checkServiceStatus(); 
});

I personally use RxJS to get me out of sticky situations like this, might be worth looking at.

EDIT:

Given feedback that RxJS is actually being used:

let observable1: Rx.Observable<something>;
let observable2: Rx.Observable<something>;

let combinedObservable = Rx.Observable
    .zip(
        observable1.take(1), 
        observable2.take(1),
        (result1, result2) => {
            // you can return whatever you want here
            return { result1, result2 };
        });

combinedObservable
    .subscribe(combinedResult => {
        // here both observable1 and observable2 will be done.
    });

This example will run both observables in parallel and combine the result into one result when they are both done.

Upvotes: 5

Vince
Vince

Reputation: 1851

You could nest your function calls.

EG:

function getDataA (callback) {
    var dataA = {test:"Hello Data A"};
    callback && callback(dataA);
}

function getDataB (callback) {
    var dataB = {test:"Hello Data B"};
    callback && callback(dataB);
}

getDataA(function (dataA) {
    getDataB(function (dataB) {
        console.log("Both functions are complete and you have data:");
        console.log(dataA);
        console.log(dataB);
    });
});

Upvotes: 0

Brant
Brant

Reputation: 1788

You could pass getDataA and getDataB callbacks in their function definitions, then call whatever you want in order:

function getDataA(callback) {
     // do some stuff
     callback && callback();
}

function getDataB(callback) {
     // do some stuff
     callback && callback();
}

function toCallAfterBoth() {
    // do some stuff
}
getDataA(getDataB(toCallAfterBoth));

Upvotes: 1

Related Questions