Show spinner GIF during an $http request in AngularJS?
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:
- for example: don't show
spinner
whenresponse.background === true;
- Intercept
request
and/orresponse
to set$rootScope.$broadcast("loader_show");
or$rootScope.$broadcast("loader_hide");