在angular度显示$ http请求期间显示Spinner GIF

我正在使用angular度的$http服务来发出ajax请求。

如何在ajax请求期间显示加载器gif?

我没有在文档中看到任何ajaxstartevent或类似的事件。

以下是目前的 AngularJS咒语:

 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']). //....... 

这是其余的(HTML / CSS)….使用

 $('#mydiv').show(); $('#mydiv').hide(); 

切换它。 注意:以上是用于angular度模块在开始的职位

 #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/jQueryhttp://img.dovov.comajax-loader.gif" class="ajax-loader"/> </div> 

这真的取决于你的具体用例,但一个简单的方法会遵循这样的模式:

 .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; }); }); 

然后在你的模板中对它做出反应:

 <div class="spinner" ng-show="loading"></div> <div ng-repeat="item in items>{{item.name}}</div> 

这是一个使用directiveng-hide

这将通过angular度的$http服务在所有调用中显示加载器。

在模板中:

<div class="loader" data-loading></div>

指示:

 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'); } }); } }; }]); 

通过在元素上使用ng-hide类,可以避免使用jquery。


自定义:添加一个interceptor

如果您创build加载拦截器,则可以根据条件显示/隐藏加载器。

指示:

 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'); }); }; }; 

拦截器:

  • 例如:当response.background === true;时不显示spinner response.background === true;
  • 拦截request和/或response设置$rootScope.$broadcast("loader_show");$rootScope.$broadcast("loader_hide");

有关编写拦截器的更多信息

如果您使用的是ngResource,则对象的$ resolved属性对于加载器非常有用:

对于一个资源如下:

 var User = $resource('/user/:id', {id:'@id'}); var user = User.get({id: 1}) 

您可以将加载器链接到资源对象的$ resolved属性:

 <div ng-hide="user.$resolved">Loading ...</div> 

https://github.com/wongatech/angular-http-loader是一个很好的项目。;

这里的例子http://wongatech.github.io/angular-http-loader/

下面的代码显示了请求发生时的模板示例/ loader.tpl.html。

 <div ng-http-loader template="example/loader.tpl.html"></div> 

刚刚发现了根据一些asynchronous调用显示一个小加载器的angular-busy指令。

例如,如果您必须进行GET ,请参阅$scope的promise,

 $scope.req = $http.get('http://google.fr'); 

并像这样调用它:

 <div cg-busy="req"></div> 

这是GitHub

您也可以使用bower安装(不要忘记更新您的项目依赖关系):

 bower install angular-busy --save 

如果你在一个服务/工厂内打包你的API调用,那么你可以在那里跟踪加载计数器(每个回答和@JMaylin出色的同时提示),并通过指令引用加载计数器。 或者其任何组合。

API WRAPPER

 yourModule .factory('yourApi', ['$http', function ($http) { var api = {} //#region ------------ spinner ------------- // ajax loading counter api._loading = 0; /** * Toggle check */ api.isOn = function () { return api._loading > 0; } /** * Based on a configuration setting to ignore the loading spinner, update the loading counter * (for multiple ajax calls at one time) */ api.spinner = function(delta, config) { // if we haven't been told to ignore the spinner, change the loading counter // so we can show/hide the spinner if (NG.isUndefined(config.spin) || config.spin) api._loading += delta; // don't let runaway triggers break stuff... if (api._loading < 0) api._loading = 0; console.log('spinner:', api._loading, delta); } /** * Track an ajax load begin, if not specifically disallowed by request configuration */ api.loadBegin = function(config) { api.spinner(1, config); } /** * Track an ajax load end, if not specifically disallowed by request configuration */ api.loadEnd = function (config) { api.spinner(-1, config); } //#endregion ------------ spinner ------------- var baseConfig = { method: 'post' // don't need to declare `spin` here } /** * $http wrapper to standardize all api calls * @param args stuff sent to request * @param config $http configuration, such as url, methods, etc */ var callWrapper = function(args, config) { var p = angular.extend(baseConfig, config); // override defaults // fix for 'get' vs 'post' param attachment if (!angular.isUndefined(args)) p[p.method == 'get' ? 'params' : 'data'] = args; // trigger the spinner api.loadBegin(p); // make the call, and turn of the spinner on completion // note: may want to use `then`/`catch` instead since `finally` has delayed completion if down-chain returns more promises return $http(p)['finally'](function(response) { api.loadEnd(response.config); return response; }); } api.DoSomething = function(args) { // yes spinner return callWrapper(args, { cache: true }); } api.DoSomethingInBackground = function(args) { // no spinner return callWrapper(args, { cache: true, spin: false }); } // expose return api; }); 

斯皮纳指示

 (function (NG) { var loaderTemplate = '<div class="ui active dimmer" data-ng-show="hasSpinner()"><div class="ui large loader"></div></div>'; /** * Show/Hide spinner with ajax */ function spinnerDirective($compile, api) { return { restrict: 'EA', link: function (scope, element) { // listen for api trigger scope.hasSpinner = api.isOn; // attach spinner html var spin = NG.element(loaderTemplate); $compile(spin)(scope); // bind+parse element.append(spin); } } } NG.module('yourModule') .directive('yourApiSpinner', ['$compile', 'yourApi', spinnerDirective]); })(angular); 

用法

 <div ng-controller="myCtrl" your-api-spinner> ... </div> 

对于页面加载和模式,最简单的方法是使用ng-show direcive并使用其中一个范围数据variables。 像ng-show =“angular.isUndefined(scope.data.someobject)”。 由于数据未定,微调将显示。 一旦服务返回数据和范围填充,微调将被隐藏。

这是最简单的方法来添加一个微调我猜: –

你可以使用ng-show与这些美丽的纺纱厂的任何一个的div标签http://tobiasahlin.com/spinkit/ {{这不是我的页面}}

然后你可以使用这种逻辑

 //ajax start $scope.finderloader=true; $http({ method :"POST", url : "your URL", data: { //your data } }).then(function mySucces(response) { $scope.finderloader=false; $scope.search=false; $scope.myData =response.data.records; }); //ajax end 
 <div ng-show="finderloader" class=spinner></div> //add this in your HTML at right place 
 Based on Josh David Miller response: <body> <header> </header> <div class="spinner" ng-show="loading"> <div class="loader" ></div> </div> <div ng-view=""></div> <footer> </footer> </body> 

添加这个CSS:

  .loader { border: 16px solid #f3f3f3; border-radius: 50%; border-top: 16px solid #3498db; border-bottom : 16px solid black; width: 80px; height: 80px; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; position: absolute; top: 45%; left: 45%; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .spinner{ width: 100%; height: 100%; z-index: 10000; position: absolute; top: 0; left: 0; margin: 0 auto; text-align: center; vertical-align: middle; background: white; opacity: 0.6; } 

而只是在你的angular度添加:

$ rootScope.loading = false; $ rootScope.loading = true; – > $ http.get结束时。

这适用于我:

HTML:

  <div id="loader" class="ng-hide" ng-show="req.$$state.pending"> <img class="ajax-loader" width="200" height="200" src="http://img.dovov.comspinner.gif" /> </div> 

angular度:

  $scope.req = $http.get("/admin/view/"+id).success(function(data) { $scope.data = data; }); 

虽然从$ http返回的承诺正在等待,但ng-show将评估为“truthy”。 一旦承诺解决了,这将自动更新……这正是我们想要的。

用下面的截取器在http请求上显示加载条

 'use strict'; appServices.factory('authInterceptorService', ['$q', '$location', 'localStorage','$injector','$timeout', function ($q, $location, localStorage, $injector,$timeout) { var authInterceptorServiceFactory = {}; var requestInitiated; //start loading bar var _startLoading = function () { console.log("error start loading"); $injector.get("$ionicLoading").show(); } //stop loading bar var _stopLoading = function () { $injector.get("$ionicLoading").hide(); } //request initiated var _request = function (config) { requestInitiated = true; _startLoading(); config.headers = config.headers || {}; var authDataInitial = localStorage.get('authorizationData'); if (authDataInitial && authDataInitial.length > 2) { var authData = JSON.parse(authDataInitial); if (authData) { config.headers.Authorization = 'Bearer ' + authData.token; } } return config; } //request responce error var _responseError = function (rejection) { _stopLoading(); if (rejection.status === 401) { $location.path('/login'); } return $q.reject(rejection); } //request error var _requestError = function (err) { _stopLoading(); console.log('Request Error logging via interceptor'); return err; } //request responce var _response = function(response) { requestInitiated = false; // Show delay of 300ms so the popup will not appear for multiple http request $timeout(function() { if(requestInitiated) return; _stopLoading(); console.log('Response received with interceptor'); },300); return response; } authInterceptorServiceFactory.request = _request; authInterceptorServiceFactory.responseError = _responseError; authInterceptorServiceFactory.requestError = _requestError; authInterceptorServiceFactory.response = _response; return authInterceptorServiceFactory; }]); 

在@bulltorious中分享我的版本,为更新的angular色版本(我使用版本1.5.8和这个代码)进行了更新,并且还结合了@ JMaylin的使用计数器的思想,以便对多个同时发生的请求选项跳过显示请求的animationless于一些最小的毫秒数:

 var app = angular.module('myApp'); var BUSY_DELAY = 1000; // Will not show loading graphic until 1000ms have passed and we are still waiting for responses. app.config(function ($httpProvider) { $httpProvider.interceptors.push('busyHttpInterceptor'); }) .factory('busyHttpInterceptor', ['$q', '$timeout', function ($q, $timeout) { var counter = 0; return { request: function (config) { counter += 1; $timeout( function () { if (counter !== 0) { angular.element('#busy-overlay').show(); } }, BUSY_DELAY); return config; }, response: function (response) { counter -= 1; if (counter === 0) { angular.element('#busy-overlay').hide(); } return response; }, requestError: function (rejection) { counter -= 1; if (counter === 0) { angular.element('#busy-overlay').hide(); } return rejection; }, responseError: function (rejection) { counter -= 1; if (counter === 0) { angular.element('#busy-overlay').hide(); } return rejection; } } }]); 
 .factory('authHttpResponseInterceptor', ['$q', function ($q) { return { request: function(config) { angular.element('#spinner').show(); return config; }, response : function(response) { angular.element('#spinner').fadeOut(3000); return response || $q.when(response); }, responseError: function(reason) { angular.element('#spinner').fadeOut(3000); return $q.reject(reason); } }; }]); .config(['$routeProvider', '$locationProvider', '$translateProvider', '$httpProvider', function ($routeProvider, $locationProvider, $translateProvider, $httpProvider) { $httpProvider.interceptors.push('authHttpResponseInterceptor'); } ]); in your Template <div id="spinner"></div> css #spinner, #spinner:after { border-radius: 50%; width: 10em; height: 10em; background-color: #A9A9A9; z-index: 10000; position: absolute; left: 50%; bottom: 100px; } @-webkit-keyframes load8 { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } @keyframes load8 { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } 

用这个代码创build指令:

 $scope.$watch($http.pendingRequests, toggleLoader); function toggleLoader(status){ if(status.length){ element.addClass('active'); } else { element.removeClass('active'); } } 

显示不同url更改之间加载的另一个解决scheme是:

 $rootScope.$on('$locationChangeStart', function() { $scope.loading++; }); $rootScope.$on('$locationChangeSuccess', function() { $timeout(function() { $scope.loading--; }, 300); }); 

然后在标记中,用ng-show="loading"切换微调。

如果要在ajax请求上显示它,只需在请求开始时添加$scope.loading++ ,并在结束时添加$scope.loading--

你也可以尝试这样的事情:

创build指令:

 myApp.directive('loader', function () { return { restrict: 'A', scope: {cond: '=loader'}, template: '<span ng-if="isLoading()" class="soft"><span class="fa fa-refresh fa-spin"></span></span>', link: function (scope) { scope.isLoading = function() { var ret = scope.cond === true || ( scope.cond && scope.cond.$$state && angular.isDefined(scope.cond.$$state.status) && scope.cond.$$state.status === 0 ); return ret; } } }; }); 

然后你添加这样的mainCtrl

  // Return TRUE if some request is LOADING, else return FALSE $scope.isLoading = function() { return $http.pendingRequests.length > 0; }; 

而HTML可以像这样:

 <div class="buttons loader"> <span class="icon" loader="isLoading()"></span> </div> 

以下方式将logging所有请求,并且只在所有请求完成后才隐藏:

 app.factory('httpRequestInterceptor', function(LoadingService, requestCount) { return { request: function(config) { if (!config.headers.disableLoading) { requestCount.increase(); LoadingService.show(); } return config; } }; }).factory('httpResponseInterceptor', function(LoadingService, $timeout, error, $q, requestCount) { function waitAndHide() { $timeout(function() { if (requestCount.get() === 0){ LoadingService.hide(); } else{ waitAndHide(); } }, 300); } return { response: function(config) { requestCount.descrease(); if (requestCount.get() === 0) { waitAndHide(); } return config; }, responseError: function(config) { requestCount.descrease(); if (requestCount.get() === 0) { waitAndHide(); } var deferred = $q.defer(); error.show(config.data, function() { deferred.reject(config); }); return deferred.promise; } }; }).factory('requestCount', function() { var count = 0; return { increase: function() { count++; }, descrease: function() { if (count === 0) return; count--; }, get: function() { return count; } }; }) 

由于position:fixed的function最近改变了,所以我很难在所有元素上显示gif loader,所以我不得不使用angular的内置jQuery

HTML

 <div ng-controller="FetchController"> <div id="spinner"></div> </div> 

CSS

 #spinner {display: none} body.spinnerOn #spinner { /* body tag not necessary actually */ display: block; height: 100%; width: 100%; background: rgba(207, 13, 48, 0.72) url(img/loader.gif) center center no-repeat; position: fixed; top: 0; left: 0; z-index: 9999; } body.spinnerOn main.content { position: static;} /* and whatever content needs to be moved below your fixed loader div */ 

调节器

 app.controller('FetchController', ['$scope', '$http', '$templateCache', '$location', '$q', function($scope, $http, $templateCache, $location, $q) { angular.element('body').addClass('spinnerOn'); // add Class to body to show spinner $http.post( // or .get( // your data here }) .then(function (response) { console.info('success'); angular.element('body').removeClass('spinnerOn'); // hide spinner return response.data; }, function (response) { console.info('error'); angular.element('body').removeClass('spinnerOn'); // hide spinner }); }) 

希望这可以帮助 :)

所有的答案都是复杂的,或者需要为每个请求设置一些variables,这是非常错误的做法,如果我们知道DRY的概念。 这里简单的拦截器的例子,我把鼠标放在ajax启动时的等待,当ajax结束时将它设置为auto。

 $httpProvider.interceptors.push(function($document) { return { 'request': function(config) { // here ajax start // here we can for example add some class or show somethin $document.find("body").css("cursor","wait"); return config; }, 'response': function(response) { // here ajax ends //here we should remove classes added on request start $document.find("body").css("cursor","auto"); return response; } }; }); 

代码必须在应用程序configurationapp.config添加。 我展示了如何在加载状态下更改鼠标,但在那里可以显示/隐藏任何加载器内容,或添加,删除一些显示加载器的CSS类。

拦截器将在每个Ajax调用中运行,所以不需要在每个http调用上创build特殊的布尔variables($ scope.loading = true / false等)

这是我的实现,就像一个ng-show和一个请求计数器一样简单。

它使用一个新的服务的所有请求$ http:

 myApp.service('RqstSrv', [ '$http', '$rootScope', function($http, $rootScope) { var rqstService = {}; rqstService.call = function(conf) { $rootScope.currentCalls = !isNaN($rootScope.currentCalls) ? $rootScope.currentCalls++ : 0; $http(conf).then(function APICallSucceed(response) { // Handle success }, function APICallError(response) { // Handle error }).then(function() { $rootScope.currentCalls--; }); } } ]); 

然后,您可以使用您的加载器基于当前调用的数量:

 <img data-ng-show="currentCalls > 0" src="images/ajax-loader.gif"/> 

这是我的解决scheme,我觉得很多easer其他张贴在这里。 不知道这是多么“美丽”,但它解决了我所有的问题

我有一个称为“加载”的CSS样式

 .loading { display: none; } 

加载div的html可以是任何,但我用一些FontAwesome图标和旋转的方法在那里:

 <div style="text-align:center" ng-class="{ 'loading': !loading }"> <br /> <h1><i class="fa fa-refresh fa-spin"></i> Loading data</h1> </div> 

在你想要隐藏的元素上,你只需写下这个:

 <something ng-class="{ 'loading': loading }" class="loading"></something> 

在函数中我只是设置这个负载。

 (function (angular) { function MainController($scope) { $scope.loading = true 

我正在使用SignalR,所以在hubProxy.client.allLocks函数(当它完成通过锁),我直接把

  $scope.loading = false $scope.$apply(); 

当页面加载时,这也隐藏了{{someField}},因为我正在加载加载类,AngularJS在之后删除它。