Angularjs加载ajax请求的屏幕
使用Angularjs,我需要显示一个加载屏幕(一个简单的微调),直到ajax请求完成。 请使用代码片段提出任何想法。
而不是设置一个范围variables来指示数据加载状态,最好有一个指令为你做所有事情:
angular.module('directive.loading', []) .directive('loading', ['$http' ,function ($http) { return { restrict: 'A', link: function (scope, elm, attrs) { scope.isLoading = function () { return $http.pendingRequests.length > 0; }; scope.$watch(scope.isLoading, function (v) { if(v){ elm.show(); }else{ elm.hide(); } }); } }; }]);
通过这个指令,你所需要做的就是给任何加载animation元素一个“加载”属性:
<div class="loading-spiner-holder" data-loading ><div class="loading-spiner"><img src="..." /></div></div>
你可以在页面上有多个加载旋钮。 在哪里以及如何布置这些纺纱器取决于您,指令将自动为您打开/closures。
这是一个例子。 它使用简单的ng-show方法和一个bool。
HTML
<div ng-show="loading" class="loading"><img src="...">LOADING...</div> <div ng-repeat="car in cars"> <li>{{car.name}}</li> </div> <button ng-click="clickMe()" class="btn btn-primary">CLICK ME</button>
ANGULARJS
$scope.clickMe = function() { $scope.loading = true; $http.get('test.json') .success(function(data) { $scope.cars = data[0].cars; $scope.loading = false; }); }
当然,您可以将加载框html代码移动到指令中,然后在$ scope.loading上使用$ watch。 在这种情况下:
HTML :
<loading></loading>
ANGULARJS指导 :
.directive('loading', function () { return { restrict: 'E', replace:true, template: '<div class="loading"><img src="..."/>LOADING...</div>', link: function (scope, element, attr) { scope.$watch('loading', function (val) { if (val) $(element).show(); else $(element).hide(); }); } } })
PLUNK : http : //plnkr.co/edit/AI1z21?p=preview
我为此使用ngProgress 。
将脚本/ css文件包含在HTML中后,将“ngProgress”添加到您的依赖关系中。 一旦你这样做,你可以设置这样的事情,当检测到路由变化时会触发。
angular.module('app').run(function($rootScope, ngProgress) { $rootScope.$on('$routeChangeStart', function(ev,data) { ngProgress.start(); }); $rootScope.$on('$routeChangeSuccess', function(ev,data) { ngProgress.complete(); }); });
对于AJAX请求,你可以做这样的事情:
$scope.getLatest = function () { ngProgress.start(); $http.get('/latest-goodies') .success(function(data,status) { $scope.latest = data; ngProgress.complete(); }) .error(function(data,status) { ngProgress.complete(); }); };
只要记得在控制器依赖关系中添加'ngProgress'就可以了。 如果您正在执行多个AJAX请求,请在主应用程序作用域中使用增量variables,以在调用“ngProgress.complete();”之前跟踪您的AJAX请求何时完成。
使用pendingRequests是不正确的,因为正如在Angular文档中提到的,这个属性主要用于debugging目的。
我推荐的是使用拦截器来知道是否有任何活动的asynchronous调用。
module.config(['$httpProvider', function ($httpProvider) { $httpProvider.interceptors.push(function ($q, $rootScope) { if ($rootScope.activeCalls == undefined) { $rootScope.activeCalls = 0; } return { request: function (config) { $rootScope.activeCalls += 1; return config; }, requestError: function (rejection) { $rootScope.activeCalls -= 1; return rejection; }, response: function (response) { $rootScope.activeCalls -= 1; return response; }, responseError: function (rejection) { $rootScope.activeCalls -= 1; return rejection; } }; }); }]);
然后通过$ watch检查指令中的activeCalls是否为零。
module.directive('loadingSpinner', function ($http) { return { restrict: 'A', replace: true, template: '<div class="loader unixloader" data-initialize="loader" data-delay="500"></div>', link: function (scope, element, attrs) { scope.$watch('activeCalls', function (newVal, oldVal) { if (newVal == 0) { $(element).hide(); } else { $(element).show(); } }); } }; });
最好的方法是使用响应拦截器和自定义指令 。 使用$ rootScope。$ broadcast & $ rootScope。$方法的pub / sub机制可以进一步改进这个过程。
由于整个过程在一篇写得很好的博客文章中有记载,所以我不再重复。 请参阅这篇文章,以提出您需要的实施。
参考这个答案
https://stackoverflow.com/a/17144634/4146239
对我来说是最好的解决scheme,但有一种方法可以避免使用jQuery。
.directive('loading', function () { return { restrict: 'E', replace:true, template: '<div class="loading"><img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" width="20" height="20" />LOADING...</div>', link: function (scope, element, attr) { scope.$watch('loading', function (val) { if (val) scope.loadingStatus = 'true'; else scope.loadingStatus = 'false'; }); } } }) .controller('myController', function($scope, $http) { $scope.cars = []; $scope.clickMe = function() { scope.loadingStatus = 'true' $http.get('test.json') .success(function(data) { $scope.cars = data[0].cars; $scope.loadingStatus = 'false'; }); } });
<body ng-app="myApp" ng-controller="myController" ng-init="loadingStatus='true'"> <loading ng-show="loadingStatus" ></loading> <div ng-repeat="car in cars"> <li>{{car.name}}</li> </div> <button ng-click="clickMe()" class="btn btn-primary">CLICK ME</button> </body>
打字稿和angular落实施
指示
((): void=> { "use strict"; angular.module("app").directive("busyindicator", busyIndicator); function busyIndicator($http:ng.IHttpService): ng.IDirective { var directive = <ng.IDirective>{ restrict: "A", link(scope: Scope.IBusyIndicatorScope) { scope.anyRequestInProgress = () => ($http.pendingRequests.length > 0); scope.$watch(scope.anyRequestInProgress, x => { if (x) { scope.canShow = true; } else { scope.canShow = false; } }); } }; return directive; } })();
范围
module App.Scope { export interface IBusyIndicatorScope extends angular.IScope { anyRequestInProgress: any; canShow: boolean; } }
模板
<div id="activityspinner" ng-show="canShow" class="show" data-busyindicator> </div> CSS #activityspinner { display : none; } #activityspinner.show { display : block; position : fixed; z-index: 100; background-image : url('data:image/gif;base64,R0lGODlhNgA3APMAAPz8/GZmZqysrHV1dW1tbeXl5ZeXl+fn59nZ2ZCQkLa2tgAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAANgA3AAAEzBDISau9OOvNu/9gKI5kaZ4lkhBEgqCnws6EApMITb93uOqsRC8EpA1Bxdnx8wMKl51ckXcsGFiGAkamsy0LA9pAe1EFqRbBYCAYXXUGk4DWJhZN4dlAlMSLRW80cSVzM3UgB3ksAwcnamwkB28GjVCWl5iZmpucnZ4cj4eWoRqFLKJHpgSoFIoEe5ausBeyl7UYqqw9uaVrukOkn8LDxMXGx8ibwY6+JLxydCO3JdMg1dJ/Is+E0SPLcs3Jnt/F28XXw+jC5uXh4u89EQAh+QQJCgAAACwAAAAANgA3AAAEzhDISau9OOvNu/9gKI5kaZ5oqhYGQRiFWhaD6w6xLLa2a+iiXg8YEtqIIF7vh/QcarbB4YJIuBKIpuTAM0wtCqNiJBgMBCaE0ZUFCXpoknWdCEFvpfURdCcM8noEIW82cSNzRnWDZoYjamttWhphQmOSHFVXkZecnZ6foKFujJdlZxqELo1AqQSrFH1/TbEZtLM9shetrzK7qKSSpryixMXGx8jJyifCKc1kcMzRIrYl1Xy4J9cfvibdIs/MwMue4cffxtvE6qLoxubk8ScRACH5BAkKAAAALAAAAAA2ADcAAATOEMhJq7046827/2AojmRpnmiqrqwwDAJbCkRNxLI42MSQ6zzfD0Sz4YYfFwyZKxhqhgJJeSQVdraBNFSsVUVPHsEAzJrEtnJNSELXRN2bKcwjw19f0QG7PjA7B2EGfn+FhoeIiYoSCAk1CQiLFQpoChlUQwhuBJEWcXkpjm4JF3w9P5tvFqZsLKkEF58/omiksXiZm52SlGKWkhONj7vAxcbHyMkTmCjMcDygRNAjrCfVaqcm11zTJrIjzt64yojhxd/G28XqwOjG5uTxJhEAIfkECQoAAAAsAAAAADYANwAABM0QyEmrvTjrzbv/YCiOZGmeaKqurDAMAlsKRE3EsjjYxJDrPN8PRLPhhh8XDMk0KY/OF5TIm4qKNWtnZxOWuDUvCNw7kcXJ6gl7Iz1T76Z8Tq/b7/i8qmCoGQoacT8FZ4AXbFopfTwEBhhnQ4w2j0GRkgQYiEOLPI6ZUkgHZwd6EweLBqSlq6ytricICTUJCKwKkgojgiMIlwS1VEYlspcJIZAkvjXHlcnKIZokxJLG0KAlvZfAebeMuUi7FbGz2z/Rq8jozavn7Nev8CsRACH5BAkKAAAALAAAAAA2ADcAAATLEMhJq7046827/2AojmRpnmiqrqwwDAJbCkRNxLI42MSQ6zzfD0Sz4YYfFwzJNCmPzheUyJuKijVrZ2cTlrg1LwjcO5HFyeoJeyM9U++mfE6v2+/4PD6O5F/YWiqAGWdIhRiHP4kWg0ONGH4/kXqUlZaXmJlMBQY1BgVuUicFZ6AhjyOdPAQGQF0mqzauYbCxBFdqJao8rVeiGQgJNQkIFwdnB0MKsQrGqgbJPwi2BMV5wrYJetQ129x62LHaedO21nnLq82VwcPnIhEAIfkECQoAAAAsAAAAADYANwAABMwQyEmrvTjrzbv/YCiOZGmeaKqurDAMAlsKRE3EsjjYxJDrPN8PRLPhhh8XDMk0KY/OF5TIm4qKNWtnZxOWuDUvCNw7kcXJ6gl7Iz1T76Z8Tq/b7/g8Po7kX9haKoAZZ0iFGIc/iRaDQ40Yfj+RepSVlpeYAAgJNQkIlgo8NQqUCKI2nzNSIpynBAkzaiCuNl9BIbQ1tl0hraewbrIfpq6pbqsioaKkFwUGNQYFSJudxhUFZ9KUz6IGlbTfrpXcPN6UB2cHlgfcBuqZKBEAIfkECQoAAAAsAAAAADYANwAABMwQyEmrvTjrzbv/YCiOZGmeaKqurDAMAlsKRE3EsjjYxJDrPN8PRLPhhh8XDMk0KY/OF5TIm4qKNWtnZxOWuDUvCNw7kcXJ6gl7Iz1T76Z8Tq/b7yJEopZA4CsKPDUKfxIIgjZ+P3EWe4gECYtqFo82P2cXlTWXQReOiJE5bFqHj4qiUhmBgoSFho59rrKztLVMBQY1BgWzBWe8UUsiuYIGTpMglSaYIcpfnSHEPMYzyB8HZwdrqSMHxAbath2MsqO0zLLorua05OLvJxEAIfkECQoAAAAsAAAAADYANwAABMwQyEmrvTjrzbv/YCiOZGmeaKqurDAMAlsKRE3EsjjYxJDrPN8PRLPhfohELYHQuGBDgIJXU0Q5CKqtOXsdP0otITHjfTtiW2lnE37StXUwFNaSScXaGZvm4r0jU1RWV1hhTIWJiouMjVcFBjUGBY4WBWw1A5RDT3sTkVQGnGYYaUOYPaVip3MXoDyiP3k3GAeoAwdRnRoHoAa5lcHCw8TFxscduyjKIrOeRKRAbSe3I9Um1yHOJ9sjzCbfyInhwt3E2cPo5dHF5OLvJREAOwAAAAAAAAAAAA==') -ms-opacity : 0.4; opacity : 0.4; background-repeat : no-repeat; background-position : center; left : 0; bottom : 0; right : 0; top : 0; }
另外还有一个很好的演示,展示了如何在项目中使用Angularjs
animation。
链接在这里
http://yearofmoo-articles.github.io/angularjs-animation-article/app/#/ng-repeat (见左上angular) 。
这是一个开源的。 这里是链接下载
https://github.com/yearofmoo-articles/AngularJS-Animation-Article
这里是教程的链接;
http://www.yearofmoo.com/2013/04/animation-in-angularjs.html
我的观点是,继续下载源文件,然后看看他们是如何实现微调。 他们可能会用一点点更好的方法。 所以,结帐这个项目。
如果你正在使用Restangular(这很棒),你可以在api调用期间创build一个animation。 这是我的解决scheme。 添加一个响应拦截器和一个发送一个rootcope广播的请求拦截器。 然后创build一个指令来监听这个响应和请求:
angular.module('mean.system') .factory('myRestangular',['Restangular','$rootScope', function(Restangular,$rootScope) { return Restangular.withConfig(function(RestangularConfigurer) { RestangularConfigurer.setBaseUrl('http://localhost:3000/api'); RestangularConfigurer.addResponseInterceptor(function(data, operation, what, url, response, deferred) { var extractedData; // .. to look for getList operations if (operation === 'getList') { // .. and handle the data and meta data extractedData = data.data; extractedData.meta = data.meta; } else { extractedData = data.data; } $rootScope.$broadcast('apiResponse'); return extractedData; }); RestangularConfigurer.setRequestInterceptor(function (elem, operation) { if (operation === 'remove') { return null; } return (elem && angular.isObject(elem.data)) ? elem : {data: elem}; }); RestangularConfigurer.setRestangularFields({ id: '_id' }); RestangularConfigurer.addRequestInterceptor(function(element, operation, what, url) { $rootScope.$broadcast('apiRequest'); return element; }); }); }]);
这是指令:
angular.module('mean.system') .directive('smartLoadingIndicator', function($rootScope) { return { restrict: 'AE', template: '<div ng-show="isAPICalling"><p><i class="fa fa-gear fa-4x fa-spin"></i> Loading</p></div>', replace: true, link: function(scope, elem, attrs) { scope.isAPICalling = false; $rootScope.$on('apiRequest', function() { scope.isAPICalling = true; }); $rootScope.$on('apiResponse', function() { scope.isAPICalling = false; }); } }; }) ;
把这个包含在你的“app.config”中:
$httpProvider.interceptors.push('myHttpInterceptor');
并添加以下代码:
app.factory('myHttpInterceptor', function ($q, $window,$rootScope) { $rootScope.ActiveAjaxConectionsWithouthNotifications = 0; var checker = function(parameters,status){ //YOU CAN USE parameters.url TO IGNORE SOME URL if(status == "request"){ $rootScope.ActiveAjaxConectionsWithouthNotifications+=1; $('#loading_view').show(); } if(status == "response"){ $rootScope.ActiveAjaxConectionsWithouthNotifications-=1; } if($rootScope.ActiveAjaxConectionsWithouthNotifications<=0){ $rootScope.ActiveAjaxConectionsWithouthNotifications=0; $('#loading_view').hide(); } }; return { 'request': function(config) { checker(config,"request"); return config; }, 'requestError': function(rejection) { checker(rejection.config,"request"); return $q.reject(rejection); }, 'response': function(response) { checker(response.config,"response"); return response; }, 'responseError': function(rejection) { checker(rejection.config,"response"); return $q.reject(rejection); } }; });
使用angular度繁忙 :
将cgBusy添加到您的应用程序/模块中:
angular.module('your_app', ['cgBusy']);
添加您的承诺scope
:
function MyCtrl($http, User) { //using $http this.isBusy = $http.get('...'); //if you have a User class based on $resource this.isBusy = User.$save(); }
在你的html模板中:
<div cg-busy="$ctrl.isBusy"></div>
这里简单的拦截器的例子,我把鼠标放在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等)。
拦截器使用jqLite构build https://docs.angularjs.org/api/ng/function/angular.element,所以不需要Jquery。;
用show和size属性创build一个指令(你也可以添加更多)
app.directive('loader',function(){ return { restrict:'EA', scope:{ show : '@', size : '@' }, template : '<div class="loader-container"><div class="loader" ng-if="show" ng-class="size"></div></div>' } })
并在html中使用
<loader show="{{loader1}}" size="sm"></loader>
在显示variables传递true时,任何承诺正在运行,并使请求完成时, 虚假 。 主动演示 – JsFiddle中的Angular Loader指令示例演示
我build立@ DavidLin的答案有点简化它 – 删除指令中的jQuery的任何依赖 。 我可以证实这一点,因为我在生产应用中使用它
function AjaxLoadingOverlay($http) { return { restrict: 'A', link: function ($scope, $element, $attributes) { $scope.loadingOverlay = false; $scope.isLoading = function () { return $http.pendingRequests.length > 0; }; $scope.$watch($scope.isLoading, function (isLoading) { $scope.loadingOverlay = isLoading; }); } }; }
我使用ng-show
而不是jQuery调用来隐藏/显示<div>
。
这里是我放在开始<body>
标签下方的<div>
:
<div ajax-loading-overlay class="loading-overlay" ng-show="loadingOverlay"> <img src="Resources/Images/LoadingAnimation.gif" /> </div>
以下是提供覆盖来阻止用户界面的CSS,同时进行$ http调用的CSS:
.loading-overlay { position: fixed; z-index: 999; height: 2em; width: 2em; overflow: show; margin: auto; top: 0; left: 0; bottom: 0; right: 0; } .loading-overlay:before { content: ''; display: block; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.3); } /* :not(:required) hides these rules from IE9 and below */ .loading-overlay:not(:required) { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; }
CSS功劳归于@Steve Seeger's – 他的职位: https ://stackoverflow.com/a/35470281/335545
您可以添加一个条件,然后通过rootcope进行更改。 在你的ajax请求之前,你只需调用$ rootScope。$ emit('stopLoader');
angular.module('directive.loading', []) .directive('loading', ['$http', '$rootScope',function ($http, $rootScope) { return { restrict: 'A', link: function (scope, elm, attrs) { scope.isNoLoadingForced = false; scope.isLoading = function () { return $http.pendingRequests.length > 0 && scope.isNoLoadingForced; }; $rootScope.$on('stopLoader', function(){ scope.isNoLoadingForced = true; }) scope.$watch(scope.isLoading, function (v) { if(v){ elm.show(); }else{ elm.hide(); } }); } }; }]);
这绝对不是最好的解决scheme,但它仍然有效。