我正在使用AngularJS的$http服务来进行Ajax请求。
如何在Ajax请求执行时显示旋转GIF(或另一种类型的忙碌指示器)?
我在AngularJS文档中没有看到类似ajaxstartevent的东西。
我正在使用AngularJS的$http服务来进行Ajax请求。
如何在Ajax请求执行时显示旋转GIF(或另一种类型的忙碌指示器)?
我在AngularJS文档中没有看到类似ajaxstartevent的东西。
当前回答
如果你正在使用ngResource,对象的$resolved属性对加载器很有用:
对于资源,如下所示:
var User = $resource('/user/:id', {id:'@id'});
var user = User.get({id: 1})
你可以将加载器链接到资源对象的$resolved属性:
<div ng-hide="user.$resolved">Loading ...</div>
其他回答
如果你在一个服务/工厂中包装你的api调用,那么你可以跟踪那里的加载计数器(每个答案和@JMaylin的优秀同步建议),并通过一个指令引用加载计数器。或其任何组合。
API 包装器
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和请求计数器一样简单。
它使用一个新的服务为所有请求$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"/>
分享来自@bulltorious的精彩答案的我的版本,更新到更新的angular构建(我使用了1.5.8版本的代码),还加入了@JMaylin的想法,使用计数器来健壮地处理多个并发请求,以及选择跳过显示小于最小毫秒数的请求动画:
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;
}
}
}]);
刚刚发现了angular-busy指令,它显示了一个依赖于某些异步调用的小加载器。
例如,如果你必须创建一个GET,在$作用域中引用承诺,
$scope.req = $http.get('http://google.fr');
像这样称呼它:
<div cg-busy="req"></div>
这是GitHub。
你也可以使用bower安装它(别忘了更新你的项目依赖项):
bower install angular-busy --save
由于position:fixed的功能最近发生了变化,我很难将gif加载器显示在所有元素之上,所以我不得不使用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
});
})
希望这对你有所帮助。