Reputation: 3489
I am trying to use an ajax spinner while a function works but I don't know how to tell the spinner to hide when the function is done.
The code works like so:
So, how do I know when the whole thing is complete so I can quit showing the spinner?
Clicking a button in the view triggers updateData()
. In my controller I have:
$scope.updateData = function () {
Data.updateData();
}
The updateData method of the Data service referenced in the above is:
updateData : function() {
API.update({
uri : 'updateData'
}, {
data : data
}, function(data) {
data = data[0];
$rootScope.$emit('Data.updateSuccess');
}, function(err) {
$rootScope.$emit('Data.updateError', err);
});
That API comes from a factory that extends $resource:
.factory('API', ['$resource', function($resource){
return $resource('/location/:uri', {}, {
query : {
method : 'GET',
isArray : true
},
update: {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
},
create: {
method: 'POST',
isArray : true,
headers: {
'Content-Type': 'application/json'
}
}
});
}]);
}
At first I thought I could listen for those $emits (I also tried $broadcast) in the controller with
$rootScope.$on('Data.updateSuccess', $log.log('update success'));
$rootScope.$on('Data.updateError', $log.log('update failure'));
but when I do I get both of them every time. So what do I need to do to determine when to hide my ajax spinner at the completion of this update process?
Upvotes: 1
Views: 809
Reputation: 160
Something like this ought ought work for you. $resource instances return a promise you can access (without having to inject the $q service manually):
updateData: function() {
var Data = API.update({ ... your opts ... });
// access the built-in $promise
Data.$promise.then(function(res){
// $broadcast from $rootScope
$rootScope.$broadcast('Data.updateSuccess');
}, function(err){
$rootScope.$broadcast('Data.updateError', err);
});
}
With insight from these:
Upvotes: 1
Reputation: 7521
You can use promises to handle this. For a promise, inject the $q service.
You get the deferral by calling $q.defer();
Then, you do something asynchronously. In your example, you would make the resource call. When you get the data back from the resource call, you can call deferral.resolve with the data. At that time you can also turn the spinner off, either through the $scope or by calling a service.
Here is an example service that simulates a 2 second delay in fetching data. It shows you how to use the $q service. Instead of the $timeout just imagine making your call to $resource.
app.service("myService", function($q, $timeout) {
var _this = this;
this.$q = $q;
this.$timeout = $timeout;
var stuff = [1, 2, 3];
return {
getStuff: function() {
var deferral = $q.defer();
_this.$timeout(function() {
deferral.resolve(stuff);
}, 2000);
return deferral.promise;
}
};
});
Next, this is a controller that uses the promise. Notice it turns the spinner on, then fetches the data, and turns it off once the data arrives. Again, I'm doing this through scope but you could call a service or emit an event depending on how your spinner is implemented.
app.controller("myController", function($scope, myService) {
var _this = this;
this.$scope = $scope;
this.myService = myService;
this.$scope.showSpinner = true;
this.myService.getStuff().then(function(data) {
_this.$scope.stuff = data;
_this.$scope.showSpinner = false;
});
});
Here is the full working fiddle: http://jsfiddle.net/jeremylikness/PhZYb/
Upvotes: 2