Reputation: 6291
I'm migrating some code from Silverlight to AngularJS. My Silverlight code would basically attempt to hit a web service. If it failed, it would wait a bit and try again. It would try this three times. I'm now trying to do this in AngularJS.
From my understanding, I should use an AngularJS service to hit my web service. From my understanding, promises are used. At this time, I have the following service:
'use strict';
myApp.service('$myService', function($rootScope, $http) {
this.queryAttempt = 0;
this.findRecent = function() {
this.queryAttempt = 0;
};
this.attemptToGetRecent = function() {
try {
this.queryAttempt = this.queryAttempt + 1;
if (this.recentQueryAttempt < 3) {
$http.get('http://www.someserver.com/endpoint');
} else {
console.log('signal failure');
}
} catch (ex1) {
console.log('Error Finding Recent (2).');
}
};
});
Due to the fact that promises are used, I'm a little lost. In Silverlight, I created events. My controller will call $myService.findRecent(). I want to detect success and failure. However, I also need some retry logic in there. If I didn't need the retry logic, I would just use return $http.get(...) in the findRecent function. However, with the retry logic need, I don't know how to structure my promises such that the controller is aware of a) a success and b) a failure if three attempts have been tried and failed.
Can someone show me how to tackle this scenario in the world of promises?
Upvotes: 0
Views: 169
Reputation: 3201
Let me post the code how to do it with comment below:
myApp.service('myService', function($rootScope, $http, $q) {
var findRecent - function() {
var deferred = $q.defer();
attemptToGetRecent(0, deferred);
return deferred.promise;
};
var attemptToGetRecent = function(count, deferred) {
$http.get('http://www.someserver.com/endpoint')
.success(function (response) {
deferred.resolve(response);
})
.error(function() {
if (count >= 3) {
deferred.reject();
} else {
attemptToGetRecent(count++, deffered);
}
});
};
});
$q
service, create deferred object
(a promise) yourself.attemptToGetRecent
function which will
keep calling itself recursively until the number of efforts is too
high.attemptToGetRecent
will try to call the server, if
success it resolves your promise with the data. If the call fails,
it will be called again up to 3 timers then rejecting your promiseConsumer of this code would use it this way:
myService.findRecent()
.then(function (data) {
console.log(data);
$scope.videos = data.feed.entry;
}, function() {
console.log("error");
});
};
For easier reading I removed logging with console. That can be added of course. Also it is a good habit to not name your own services with leading $, this is reserved to angular services.
Working example: http://codepen.io/anon/pen/KnCFJ
Upvotes: 1
Reputation: 370
You can inject $q and use it to make your own promise and create a recursive function to handle the attempts.
Here is some code that should help:
'use strict';
myApp.service('$myService', function ($rootScope, $http, $q) {
this.getRecent = function(){
var deferred = $q.defer();
var attempts = 0;
(function queryRecent(attempts, error){
if(attempts >= 2){
// the $http.get() failed 3 times
deferred.reject(error);
}else{
$http.get('http://www.someserver.com/endpoint').then(function(response){
// success -> resolve any data you want
deferred.resolve({
attempts: attempts,
response: response
});
}).catch(function(error){
// failed, retry the queryRecent recursive function
queryRecent(attempts + 1, error); // pass attempts + 1 and the error object
});
}
})(attempts, ''); // initially pass 0 and '' to the queryRecent recursive function
return deferred.promise;
};
});
myApp.controller('MyCtrl', function($scope, $myService){
$myService.getRecent().then(function(data){
// success -> use data
console.log(data);
}).catch(function(error){
// the $http.get() failed 3 times
console.log(error);
});
});
Upvotes: 0