Chaining promises in Angular with $q.all - angularjs

I have the following layout for a promise chain in a service...
this.getData = function(params) {
var promise = $http({}).then(function(firstdata) {
// work on the first data and then call a number of promises for fetch additional data
var promises = list.map(function(item) {
return $http({}).then(function(result2) {
// this is an amalgamation of all the data from the various calls
return finalData;
});
return $q.all(promises);
})
});
return promise;
}
Then in my controller i'm doing
myService.getData().then(function(data){
});
The issue lies in the fact that THEN in the controller executes before PROMISES (note the plural) has returned a value.
This is likely something silly but any thoughts on how to simplify this/make it work would be handy!

Currently your inner promises($q.all promise) isn't returned from promise variable. You should also return promises(plural), to make sure chain should work.
this.getData = function(params) {
var promise = $http({}).then(function(firstdata) {
// creating new promise array in `promises` function
var promises = list.map(function(item) {
return $http({}).then(function(result2) {
// this is an amalgamation of all the data from the various calls
return finalData;
});
return $q.all(promises);
});
return promises; //returning inner promise
});
return promise;
}

Related

How to get .notify() in chaining promises from $q.all?

I am using chained promises in angular js with $q service and it's working fine except the information of progressCallback ? let me draw what I have done so far?
calling function from my controller in below chainable promise way
fun1()
.then(resp1){
return fun2(resp1.id);
})
.then(resp2){
return $q.all([fun3(resp2.id),fun4(resp2.name)]);
})
.then(function(resp34){
return fun5();
})
.then(success)
.catch(errorhandler)
.finally(final);
and here is my all functions signature in service
var funX = function(param) {
var d = $q.defer();
d.notify('start with funX'); // Note: it was not working so placed inside else
doSomethingASync(param, function(err,data) {
if(err) { d.reject(err);}
else { d.notify('done with funX'); d.resolve(data); }
});
return d.promise;
});
Now my question is where do I receive this d.notify() message in my controller?
trial 1
.then(resp1, info1){
return fun2(resp1.id);
});
but it's undefined
trial 2
.then(resp1, err1, info1) {
return fun2(resp1.id);
}
but still undefined?
UPDATE
I have find a way by adding second parameter in finally()
.then().catch().finally(final, notify);
and here is my function definitions.
var errorHandler = function(err) {
console.error('Error returned from function:', err);
};
var final = function() {
console.log('Called Finally');
};
var notify = function(notification) {
console.log('Notify', notification);
};
var success = function(data) {
console.log('Success data');
console.log(data);
};
Can we get each promise function notification or this is not feasible?
But Now my query changed to
How do we add a .notify for the $q.all() ?
as I understand that $q.all returns a single promise which contains all promise resolve data;

Why won't promise resolve in a service?

I have a factory NewEditSvc where I'm trying to share functionality common to NewCtrl and EditCtrl. One thing I'm trying to do is get feeParameters from the server inside the service but this is not working.
angular.module('feeSuitesApp')
.factory('NewEditSvc', function($q, FeeTypesSvc){
var _feeParameters = {};
function getParameters(){
return _feeParameters;
}
function setParameters(feeType){
var promise = $q(function(resolve, reject){
FeeTypesSvc.resource.get({id: feeType.id, association: 'fee_parameters'}).
$promise.then(function(data){
resolve(data);
}, function(error){
reject(error);
})
});
promise.then(function(data){
_feeParameters = data.master;
});
}
return {
getParameters: getParameters,
setParameters: setParameters
}
});
angular.module('feeSuitesApp')
.controller('NewCtrl', function(NewEditSvc, feeType){
$scope.feeParameters = NewEditSvc.getParameters();
$scope.feeType = feeType;
$scope.setParameters = function(feeType){
NewEditSvc.setParameters(feeType);
};
$scope.setParameters($scope.feeType);
});
After my last line $scope.feeParameters is not set. But if I return the promise variable from NewEditSvc.setParameters() and then in my NewCtrl I do the following:
var promise = $scope.setParameters($scope.feeType);
promise.then(function(data){
$scope.feeParameters = data.master;
});
Then everything works. What am I doing wrong?
The problem is, that you're not returning your promise in setParameters. https://docs.angularjs.org/api/ng/service/$q/
Just add return promise.

Difference between var=$http and return $http

I am trying to understand the difference between those two http calls in my factory:
One: function(code) {
return $http.get('api/team/' + code)
.then(function(resp) {
return resp.data;
});
}
}
And
Two: function(code) {
var promise = $http.get('api/team/' + code);
promise.then(function(resp) {
return resp.data;
});
return promise;
}
If I use Two in resolve in config:
resolve: {
testt: ['$route','MyService',
function($route, MyService) {
return MyService.Two($route.current.params.code);
}]
}
Then I can see the data in my ng-view. If I use One, I dont see the data in ng-view.
My controller:
.controller('TeamDetailsCtrl',
['MyService','testt',
function(MyService,testt) {
var self = this;
self.team = testt.data;
}]);
So, what is the difference?
Best Regards
One: When $http.get() is done, it'll resolve and continue into the then. This returns another promise, filled with the result of the then function result.data. One returns the second promise.
Two: Returns the original promise from $http.get() with the result result, (in which you haven't transformed result into result.data). The correct syntax for two could be:
Two: function(code) {
var promise = $http.get('api/team/' + code);
var promise2 = promise.then(function(resp) {
return resp.data;
});
return promise2;
}
One returns a promise, which will eventually return resp.data.
If you use One, resp.data === testt in your controller. testt.data doesn't work because resp.data.data doesn't work.
If you want to use One, change self.team = testt.data to self.team = testt.

Chaining API calls with $q.all

I don't know
how to add the returned data from resource to the promise array correctly. When I log it to the console its empty.
Here is my code:
var d = $q.defer();
var promises = [];
_.each(recipe.credentials, function(credential) {
APIService.save({route:'credential'},credential).$promise.then(function(data) {
promises.push(data)
});
});
$q.all(promises).then(function(data) {
console.log(data);
d.resolve();
});
return d.promise;
Updated Code:
var d = $q.defer();
var promises = recipe.credentials.map(function(credential) {
return APIService.save({route:'credential'},credential).$promise;
});
return $q.all(promises)
You should wrap promises when they're created, and don't forget the .catch handler:
$q.all(recipe.credentials.map(function(credential) {
return APIService.save({route:'credential'},credential).$promise;
})).then(function(data) {
console.log(data);
}).catch(function(reason) {
console.log(reason);
});
Also, most probably there's no need to create another defer - just return the result of $q.all into outer world.
P.S. I highly recommend reading this article about promises and their usage. )

AngularJS : chaining http promises $q in a service

i have problems when it comes to $http promises in angularjs. i am doing this in my service: (the getSomething function should chain two promises)
the second function uses a external callback function!
app.service('blubb', function($http, $q) {
var self = this;
this.getSomething = function(uri, data) {
return self.getData(uri).then(function(data2) {
return self.compactData(uri, data2);
});
};
this.getData = function(uri) {
var deferred = $q.defer();
$http.get(uri).success(function(data) {
deferred.resolve(data);
}).error(function() {
deferred.reject();
});
return deferred.promise;
};
this.compactData = function(uri, data) {
var deferred = $q.defer();
/* callback function */
if(!err) {
console.log(compacted);
deferred.resolve(compacted);
} else {
console.log(err);
deferred.reject(err);
}
/* end of function */
return deferred.promise;
};
});
when i use the service in my controller it doesn't output the console.log:
blubb.getSomething(uri, input).then(function(data) {
console.log(data)
});
edit:
if i define the callback function by myself in 'compactData' it works, but i am using "jsonld.compact" from https://raw.github.com/digitalbazaar/jsonld.js/master/js/jsonld.js and THIS doesn't work!
jsonld.compact(input, context, function(err, compacted) {
if(!err) {
console.log(compacted);
deferred.resolve(compacted);
} else {
deferred.reject('JSON-LD compacting');
}
});
i am getting the console.log output in jsonld.compact but the resolve doesn't work and i don't know why..
it only works with $rootScope.$apply(deferred.resolve(compacted));
I'm using chaining promises like this:
$http.get('urlToGo')
.then(function(result1) {
console.log(result1.data);
return $http.get('urlToGo');
}).then(function(result2) {
console.log(result2.data);
return $http.get('urlToGo');
}).then(function(result3) {
console.log(result3.data);
});
Chaining promises works here : jsfiddle
In your implementation, if $http.get or compactData goes wrong your console.log(data) will not be call.
You should maybe catch errors :
blubb.getSomething(uri, input).then(function(data) {
console.log(data);
}, function(err) {
console.log("err: " + err);
});
Whenever you use an external (external to AngularJS) callback that runs in a new turn/tick, you have to call $apply() on the appropriate scope after it has been invoked. This lets AngularJS know it has to update. You'll probably want to make sure you're only calling it once -- after all of the promises have been resolved. As an aside, jsonld.js provides a promises/future API, so if you're already using promises, you don't have to do that wrapper code above. Instead you can do:
var promisesApi = jsonld.promises();
var promise = promisesApi.compact(input, context);
// do something with the promise
I would suggest you to use a Factory instead of a service.
Just return the function from the factory and use it in your controller

Resources