This really depends on your specific use case, but a simple way would follow a pattern like this:
.controller('MainCtrl', function ( $scope, myService ) {
$scope.loading = true;
myService.get().then( function ( response ) {
$scope.items = response.data;
}, function ( response ) {
// TODO: handle the error somehow
}).finally(function() {
// called no matter success or failure
$scope.loading = false;
});
});
And then react to it in your template:
<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>
Here are the current past AngularJS incantations:
angular.module('SharedServices', [])
.config(function ($httpProvider) {
$httpProvider.responseInterceptors.push('myHttpInterceptor');
var spinnerFunction = function (data, headersGetter) {
// todo start the spinner here
//alert('start spinner');
$('#mydiv').show();
return data;
};
$httpProvider.defaults.transformRequest.push(spinnerFunction);
})
// register the interceptor as a service, intercepts ALL angular ajax http calls
.factory('myHttpInterceptor', function ($q, $window) {
return function (promise) {
return promise.then(function (response) {
// do something on success
// todo hide the spinner
//alert('stop spinner');
$('#mydiv').hide();
return response;
}, function (response) {
// do something on error
// todo hide the spinner
//alert('stop spinner');
$('#mydiv').hide();
return $q.reject(response);
});
};
});
//regular angular initialization continued below....
angular.module('myApp', [ 'myApp.directives', 'SharedServices']).
//.......
Here is the rest of it (HTML / CSS)....using
$('#mydiv').show();
$('#mydiv').hide();
to toggle it. NOTE: the above is used in the angular module at beginning of post
#mydiv {
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:1000;
background-color:grey;
opacity: .8;
}
.ajax-loader {
position: absolute;
left: 50%;
top: 50%;
margin-left: -32px; /* -1 * image width / 2 */
margin-top: -32px; /* -1 * image height / 2 */
display: block;
}
<div id="mydiv">
<img src="lib/jQuery/images/ajax-loader.gif" class="ajax-loader"/>
</div>
Here's a version using a directive
and ng-hide
.
This will show the loader during all calls via angular's $http
service.
In the template:
<div class="loader" data-loading></div>
directive:
angular.module('app')
.directive('loading', ['$http', function ($http) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.isLoading = function () {
return $http.pendingRequests.length > 0;
};
scope.$watch(scope.isLoading, function (value) {
if (value) {
element.removeClass('ng-hide');
} else {
element.addClass('ng-hide');
}
});
}
};
}]);
by using the ng-hide
class on the element, you can avoid jquery.
Customize: add an interceptor
If you create a loading-interceptor, you can show/hide the loader based on a condition.
directive:
var loadingDirective = function ($rootScope) {
return function ($scope, element, attrs) {
$scope.$on("loader_show", function () {
return element.removeClass('ng-hide');
});
return $scope.$on("loader_hide", function () {
return element.addClass('ng-hide');
});
};
};
interceptor:
spinner
when response.background === true;
request
and/or response
to set $rootScope.$broadcast("loader_show");
or $rootScope.$broadcast("loader_hide");
more info on writing an interceptor
If you are using ngResource, the $resolved attribute of an object is useful for loaders:
For a resource as follows:
var User = $resource('/user/:id', {id:'@id'});
var user = User.get({id: 1})
You can link a loader to the $resolved attribute of the resource object:
<div ng-hide="user.$resolved">Loading ...</div>
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