I'd like to know if it's possible to handle the $promise returned by ngResource on multiple levels so that the code is DRY
here is a simple example
aService = function(aResource) {
var error, success;
success = function(response) {
console.log('Service Success');
};
error = function(response) {
console.log('Service Error');
};
this.servicePostReq = function() {
return aResource.save().$promise.then(success, error);
};
return this;
angular.module('app.service').factory('aService', ['aResource', aService]);
this works fine so far... it Service Success when response is OK and it Service Error when response is not OK
but when I add a controller that use this aService like following
aController = function(aService) {
var error, success;
success = function(response) {
console.log('Controller Success');
};
error = function(response) {
console.log('Controller Error');
};
this.controllerPostReq = function() {
aService.servicePostReq().then(success, error);
};
return this;
};
angular.module('app.controller').controller('aController', ['aService', aController]);
the controller always success...
so if the request return success the output is
Service Success
Controller Success
and if the request fails the output is
Service Error
Controller Success
how do I chain the promise so that I don't have to add the code handled in the service for every controller that use the service ?
The problem is your service. Change this:
this.servicePostReq = function() {
return aResource.save().$promise.then(success, error);
};
To this:
this.servicePostReq = function() {
return aResource.save().$promise.then(success);
};
Explanation:
Since your service returns aResource.save().$promise.then(success, error), it's returning a new promise with an error handler included. Later, in your controller, you add onto the chain like this.
aService.servicePostReq().then(success, error);
The complete promise chain at this point looks if you expand it out:
return aResource.save().$promise
.then(successFnFromService, errorFnFromService)
.then(successFnFromController, errorFnFromController);
Since you catch the error from aResource.save() with errorFnFromService, the promise chain is basically "clean" at this point and it will just continue with the next then.
By removing the first error handler, you allow the error to be caught later on.
A better way (in general) to handle errors in promise chains would be to use a single .catch() at the end of the chain.
Consider this bad code (try running on your browser console):
new Promise(
function(resolve, reject){
reject('first');
}).then(
function(result) {
console.log('1st success!', result);
return result;
},
function(err) {
console.log('1st error!', err);
return err;
}
).then(
function(result){
console.log('2nd success!', result);
},
function(err){
console.log("2nd error!", err);
}
);
Output:
1st error! first
2nd success! first
Better way:
new Promise(
function(resolve, reject){
reject('first');
}).then(function(result) {
console.log('1st success!', result);
return result;
}).then(function(result){
console.log('2nd success!', result);
// catch error once at the end
}).catch(function(err){
console.log("error!", err);
});
Output:
error! first
Try both of those in browser console, and change reject to resolve to see how it affects the output.
add a dependency on the $q and use $q.reject to control the execution...
in your example you need a $q.reject in the aService.error method
as mentioned here in the $q docs
reject(reason);Creates a promise that is resolved as rejected with the specified reason. This api should be used to forward rejection in a chain of promises. If you are dealing with the last promise in a promise chain, you don't need to worry about it.
When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of reject as the throw keyword in JavaScript. This also means that if you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via reject.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With