Reputation: 452
I have 2 http calls needed to be reslove before initializing my controller, currenly using Angular UI router and I have resolve map under $stateProvider.state('stateName', {stateObject}) my stateObject as bellow
$stateProvider.state('stateName', {
url : '/myURL',
params: {
data1: undefined,
data2 : undefined
},
resolve: {
dataTobeResolve : function($stateParams,$q) {
var deferred = $q.defer();
var deferredObj = {};
deferredObj.d1 = $q.defer();
deferredObj.d2 = $q.defer();
var result = {
data1: {},
data2: {}
}
if(angular.isDefined($stateParams.data1)) {
result.data1 = $stateParams.data1;
deferredObj.d1.resolve();
}
else {
httpCall().then(function(response) {
AsyncMethodCall(response.data).then(function(resolvedData) {
result.data1 = resolvedData;
deferredObj.d1.resolve();
});
});
}
if(angular.isDefined($stateParams.data2)) {
result.data2 = $stateParams.data2;
deferredObj.d2.resolve();
}
else {
AsyncMethodCall().then(function(resolvedData) {
result.data2 = resolvedData;
deferredObj.d2.resolve();
});
}
$q.all(deferredObj).then(function() {
deferred.resolve(result);
});
return deferred.promise;
}
}
});
how ever despite of deferredObj.d1 being resolve controll goes to then(function(){}) of $q.all(deferredObj) which is unexpected behaviour and I belive that all of the promise maps of deferredObj should be resolve before this line get executed, my controller get initialize despite of one of the promises being resolved
Upvotes: 0
Views: 1150
Reputation: 452
I have found the issue and it is due to passing deferred object into $q.all() rather than hash/array of promises. so following code will solve the problem
$stateProvider.state('stateName', {
url : '/myURL',
params: {
data1: undefined,
data2 : undefined
},
resolve: {
dataTobeResolve : function($stateParams,$q) {
var deferred = $q.defer();
var promises = {};
var d1 = $q.defer();
var d2 = $q.defer();
promises.d1 = d1.promise;
promises.d2 = d2.promise;
var result = {
data1: {},
data2: {}
}
if(angular.isDefined($stateParams.data1)) {
result.data1 = $stateParams.data1;
d1.resolve();
}
else {
httpCall().then(function(response) {
AsyncMethodCall(response.data).then(function(resolvedData) {
result.data1 = resolvedData;
d1.resolve();
});
});
}
if(angular.isDefined($stateParams.data2)) {
result.data2 = $stateParams.data2;
d2.resolve();
}
else {
AsyncMethodCall().then(function(resolvedData) {
result.data2 = resolvedData;
d2.resolve();
});
}
$q.all(promises).then(function() {
deferred.resolve(result);
});
return deferred.promise;
}
}
});
but still I appreciate if someone provide better solution
Upvotes: 0
Reputation: 48968
Since $q.all
, $http
, and the .then
method all returns promises, the is no need to manufacture a promise with $q.defer
. Only use $q.defer
to make promises from old style callback-only asynchronous APIs.
Use $q.when
to make a promise from a synchronous source or from a promise from outside the AngularJS framework.
resolve: {
dataTobeResolve : function($stateParams,$q) {
var d1Promise;
var d2Promise;
if(angular.isDefined($stateParams.data1)) {
d1Promise = $q.when($stateParams.data1);
}
else {
d1Promise = httpCall()
.then(function(response) {
return response.data;
});
}
if(angular.isDefined($stateParams.data2)) {
d2Promise = $q.when($stateParams.data2)
}
else {
d2Promise = httpCall2()
.then(function(response) {
return response.data;
});
}
return $q.all([d1Promise, d2Promise]);
}
}
In the above example, two promises are created by either $q.when of a parameter or derived from a promise-based asynchronous API. A composite promise is created from the two promises with the $q.all
method.
Using derived promises has the advantage that rejections are automatically carried forward to the final promise. As currently written, the $q.defer
method, will hang the state change if either of the XHR calls has an error from the server.
Upvotes: 1