Reputation: 19207
I am having a service which is calling two other async services and returns some combined data, but how can this be done in AngularJS.
I have a controller in which I would like to call these two methods similar to this:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
return 'Greetings ' + dataA + dataB;
}
Is there a smarter way than to actually nest the Then method calls like this:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff().then(function(respA){
var dataB = serviceB.GetAsyncStuff().then(function(respB){
return 'Greetings ' + respA.data + respB.data;
});
});
}
This example is of course a bit simplified.
Upvotes: 1
Views: 2859
Reputation: 32367
You need to use $q.all
:
app.factory('myService', function($q, serviceA, serviceB, serviceC){
// $http returns a response object so we need to extract the data
var fn = function(res){
return res.data;
};
var promises = [
serviceA.GetAsyncStuff().then(fn),
serviceB.GetAsyncStuff().then(fn)
];
return $q.all(promises).then(function(data){
// you can manipulate consolidated data here
// data.push(serviceC);
return data;
});
});
$q#all(promises);
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
Returns
Returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.
Upvotes: 5
Reputation: 2137
Your best bet is to use $q.all
, which makes sure that all of the requested promises have been resolved before attempting to execute a function
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
$q.all([dataA, dataB]).then(doSomething);
}
EDIT: If you need to return the data, you're going to have to return a promise. You can either just return $q.all
or resolve a new promise once $q.all
has been resolved, e.g.
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
var deferred = $q.defer();
$q.all([dataA, dataB]).then(function (promises) {
deferred.resolve('Greetings ' + promises[0] + promises[1]);
});
return deferred.promise;
}
Upvotes: 0
Reputation: 32716
You can chaining promise:
angular.module('app',[])
.factory('Service1',function($q,$timeout){
return {
f: function(){
var deferred = $q.defer();
$timeout(function() {
deferred.resolve('Service 1');
},1000);
return deferred.promise;
}
}
})
.factory('Service2',function($q,$timeout,Service1){
return {
f: function(){
var deferred = $q.defer();
Service1.f().then(function(data){
$timeout(function() {
deferred.resolve('Service 2 '+ data);
},1000);
});
return deferred.promise;
}
}
})
.controller('MainCtrl', function($scope,Service2){
var promise2 = Service2.f();
promise2.then(function(data2){
console.log(data2);
});
});
or just use
$q.all([Service1,Service2]).then
Upvotes: 0
Reputation: 443
We can call both services and return promise.
myApp.provider("myService", function($http,$q){
var serviceOneData = {},
serviceTwoData = {};
//call service 1
return {
serviceOneData : serviceOneData ,
serviceTwoData : serviceTwoData ,
getService1: function(){
var deferred = $q.defer();
$http({method: 'GET',url:'Service1',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceOneData = data;
deferred.resolve();
})
.error(function (data,status,header,config) {
deferred.reject();
});
//call service 2
return deferred.promise;
},
getService2: function(){
var Seconddeferred = $q.defer();
$http({method: 'GET',url:'Service2',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceTwoData = data;
Seconddeferred.resolve();
})
.error(function (data,status,header,config) {
Seconddeferred.reject();
});
//call service 2
return Seconddeferred.promise;
},
getService : getService1().then(getService2()).
then(
return serviceOneData + serviceTwoData
);
}
} );
Upvotes: 0
Reputation: 6619
function ServiceC(serviceA,serviceB) {
var _totalData = {};
var dataA = serviceA.GetAsyncStuff().then(function(respA){
_totalData = respA;
});
var dataB = serviceB.GetAsyncStuff().then(function(respB){
_totalData += respB;
});
return{ totalData: _totalData}
}
I say first one is better as it is having two different calls and you can add your data and return it at the end and and in your second example you using service under service that would creating a overhead for saving the value of one service till 2nd service get called and call its data, you can see the network pressure second one is taking much time to get the resources and to return the resources.
Upvotes: 0