在 AngularJS 中的 $http 请求期间显示微调器 GIF?

Posted

技术标签:

【中文标题】在 AngularJS 中的 $http 请求期间显示微调器 GIF?【英文标题】:Show spinner GIF during an $http request in AngularJS? 【发布时间】:2013-02-08 14:28:22 【问题描述】:

我正在使用 AngularJS 的$http 服务来发出 Ajax 请求。

如何在 Ajax 请求执行时显示微调器 GIF(或其他类型的忙碌指示器)?

我在 AngularJS 文档中没有看到类似 ajaxstartevent 的内容。

【问题讨论】:

如果你想要一个基于 HTTP 拦截器的简单微调器,我有一个 angular 模块。它使用流行的 Identified Sham 微调器。看一看:github.com/harinair/angular-sham-spinner 我写了一个插件angular-httpshooter,它在调用前释放一个带有配置数据的事件,在收到响应后释放另一个,你可以编写全局加载器来捕捉这些事件 【参考方案1】:

这实际上取决于您的具体用例,但一个简单的方法将遵循这样的模式:

.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>

【讨论】:

如果你同时有多个ajax请求,你可以将loading声明为整数$scope.loading = 0;,当请求开始时你做$scope.loading++;,当它结束时你做@987654326 @。模板中没有什么可以改变的。因此,当至少有一个请求正在进行时显示微调器,其余时间隐藏 您可能也应该在错误回退功能中将 loading 设置为 false。 @sebnukem 是的。这是一个相当高级的示例,但为了清楚起见,我还是继续添加了它。感谢您的反馈! @JMaylin - 然后你可以在 $scope.loading 上使用 $watch 做其他事情 一种更简洁的方法,而不是将$scope.loading = false 放在成功和失败回调中,而是将它放在.finally() 中。它看起来像:mySvc.get().then(success, fail).finally(function() $scope.loading = false; );【参考方案2】:

这里是当前过去的 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(); 

切换它。注意:以上内容在帖子开头的角度模块中使用

#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>

【讨论】:

请注意,您可以使用angular.element('#mydiv').show() 代替$('#mydiv').show() 如果您的页面发出多个 ajax 请求,这将不起作用。它会在第一个请求结束后隐藏加载 gif。 根据 AngularJS 的最佳实践(公认的解决方案违反了该实践),您不应该在指令之外修改 DOM。考虑在指令中对元素调用显示/隐藏。 我不确定我是否知道足够的评论...但是正确的方法是使用 ng-class 指令而不是使用 JQuery 来显示和隐藏元素吗?跨度> @JamesHeald 是正确的。你永远不需要在 Angular 中使用 jQuery 进行任何 dom 操作。查看:ng-class、ng-if、ng-hide、ng-show 等。几乎所有你需要的东西都有一个指令。【参考方案3】:

这是使用directiveng-hide 的版本。

这将在 all 通过 angular 的 $http 服务调用期间显示加载程序。

在模板中:

&lt;div class="loader" data-loading&gt;&lt;/div&gt;

指令:

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

如果你创建了一个加载拦截器,你可以根据条件显示/隐藏加载器。

指令:

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 拦截request和/或response以设置$rootScope.$broadcast("loader_show");$rootScope.$broadcast("loader_hide");

more info on writing an interceptor

【讨论】:

@punkrockpollly 在我的特定场景中,我有两个单独的组件调用服务。但这仅适用于其中一个,我应该传递参数还是其他东西以使其可重用? @razorblade 在任何服务中通过$http 拨打电话时,它都会旋转。【参考方案4】:

如果你使用 ngResource,对象的 $resolved 属性对加载器很有用:

对于一个资源如下:

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

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

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

【讨论】:

【参考方案5】:

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>

【讨论】:

【参考方案6】:

刚刚发现了 angular-busy 指令,它根据一些异步调用显示了一个小加载器。

例如,如果您必须创建GET,请在您的$scope 中引用承诺,

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

然后这样称呼它:

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

这里是 GitHub

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

bower install angular-busy --save

【讨论】:

我在文档中找不到如何“禁用某些元素”。你能解释一下吗?例如,我想在显示微调器时禁用按钮。 angular-busy 只给你的元素戴上面具,我认为你不能随意禁用按钮,但你可以在它上面设置背景用一个空模板来给人这种印象。我不是母语人士,很抱歉造成混淆:) 好的,我编辑了您的答案以防止其他人有同样的困惑。一个说英语的法语和另一个法语总是令人困惑:)【参考方案7】:

如果您将 api 调用包装在服务/工厂中,那么您可以在那里跟踪加载计数器(根据 answer 和 @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>

【讨论】:

【参考方案8】:

对于页面加载和模式,最简单的方法是使用 ng-show 指令并使用范围数据变量之一。比如:

ng-show="angular.isUndefined(scope.data.someObject)".

在这里,虽然someObject 未定义,但将显示微调器。一旦服务返回数据并填充了someObject,微调器将返回其隐藏状态。

【讨论】:

【参考方案9】:

我猜这是添加微调器的最简单方法:-

您可以将 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

【讨论】:

【参考方案10】:
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;

只是在你的角度添加:

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

【讨论】:

【参考方案11】:

从@bulltorious 分享我的最佳答案版本,针对更新的角度构建进行了更新(我在此代码中使用了 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;
      
    
  ]);

【讨论】:

【参考方案12】:

您可以使用 Angular 拦截器来管理 http 请求调用

  <div class="loader">
    <div id="loader"></div>
  </div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) 
        return 
            request: function ($config) 
                $('.loader').show();
                return $config;
            ,
            response: function ($config) 
                $('.loader').hide();
                return $config;
            ,
            responseError: function (response) 
                return response;
            
        ;
    ]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) 
            $httpProvider.interceptors.push('httpRequestInterceptor');
        ]);

</script>

https://***.com/a/49632155/4976786

【讨论】:

【参考方案13】:

没有拦截器或jQuery的简单方法

这是一种显示微调器的简单方法,不需要第三方库、拦截器或 jQuery。

在控制器中,设置和重置一个标志。

function starting() 
    //ADD SPINNER
    vm.starting = true;
    $http.get(url)
      .then(function onSuccess(response) 
        vm.data = response.data;
    ).catch(function onReject(errorResponse) 
        console.log(errorResponse.status);
    ).finally(function() 
        //REMOVE SPINNER
        vm.starting = false;
    );
;

在 HTML 中,使用标志:

<div ng-show="vm.starting">
    <img ng-src="spinnerURL" />
</div>

<div ng-hide="vm.starting">
    <p>vm.data</p>
</div>

vm.starting 标志在 XHR 启动时设置为 true,并在 XHR 完成时清除。

【讨论】:

【参考方案14】:

这对我很有效:

HTML:

  <div id="loader" class="ng-hide" ng-show="req.$$state.pending">
    <img class="ajax-loader" 
          
          
         src="/images/spinner.gif" />
  </div>

角度:

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

虽然从 $http 返回的承诺是未决的,但 ng-show 将评估它是“真实的”。一旦 promise 被解决,它就会自动更新......这正是我们想要的。

【讨论】:

这不是动态的方法。 您能否解释一下为什么您认为这不是实现这一目标的动态方式。这将帮助阅读这篇文章的其他人学习。谢谢。 我的应用程序中有多个请求。 $scope.req 仅适用于单个请求。当这个特定的请求完成时,加载器将隐藏并且不会等待完成其他请求。实现这一点的最佳方法是使用拦截器。【参考方案15】:

使用以下拦截器在 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;
]);

【讨论】:

【参考方案16】:
.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);
  

【讨论】:

纯代码答案没有多大用处。【参考方案17】:

使用此代码创建指令:

$scope.$watch($http.pendingRequests, toggleLoader);

function toggleLoader(status)
  if(status.length)
    element.addClass('active');
   else 
    element.removeClass('active');
  

【讨论】:

【参考方案18】:

显示不同 url 更改之间加载的另一种解决方案是:

$rootScope.$on('$locationChangeStart', function() 
  $scope.loading++;
);

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

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

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

【讨论】:

【参考方案19】:

你也可以试试这样的:

创建指令:

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>

【讨论】:

【参考方案20】:

以下方式将记录所有请求,并仅在所有请求完成后隐藏:

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

【讨论】:

【参考方案21】:

由于 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
);

)

希望这会有所帮助:)

【讨论】:

【参考方案22】:

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

$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;
      
    ;
  );

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

拦截器将在每个 ajax 调用上运行,因此无需在每个 http 调用上创建特殊的布尔变量( $scope.loading=true/false 等)

【讨论】:

【参考方案23】:

这是我的实现,就像一个 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"/>

【讨论】:

【参考方案24】:

如果您想为每个 http 请求调用显示加载器,那么您可以使用角度拦截器来管理 http 请求调用,

这是一个示例代码

<body data-ng-app="myApp">
<div class="loader">
    <div id="loader"></div>
</div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) 
        return 
            request: function ($config) 
                $('.loader').show();
                return $config;
            ,
            response: function ($config) 
                $('.loader').hide();
                return $config;
            ,
            responseError: function (response) 
                return response;
            
        ;
    ]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) 
            $httpProvider.interceptors.push('httpRequestInterceptor');
        ]);

</script>
</body>

【讨论】:

【参考方案25】:

只需使用 ng-show 和布尔值

无需使用指令,无需复杂。

这是放置在提交按钮旁边或您希望微调器所在的任何位置的代码:

<span ng-show="dataIsLoading">
  <img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" style="height:20px;"/>
</span>

然后在你的控制器中:

$scope.dataIsLoading = true

let url = '/whatever_Your_URL_Is'
$http.get(url)
.then(function(response) 
  $scope.dataIsLoading = false
)

【讨论】:

我同意你的代码,这就是我的做法,简单而且像魅力一样工作,也许我在你的代码中唯一要改变的是,不是使用布尔值,而是使用整数,而不是设置为 true 将 1 添加到 int,并扣除作为响应。 -- 在 Html 中,然后你执行 -- 这将允许同时进行多个调用,并且只有在所有调用完成后才删除加载器 【参考方案26】:

添加到@Adam 的答案,

按照建议使用 ng-show,但是,在您的情况下,您希望该功能具有多个请求并在隐藏加载程序之前等待所有请求。

<span ng-show="pendingRequests > 0">
    <img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" style="height:20px;"/>
</span>

然后在你的控制器中:

$scope.pendingRequests++;

let url = '/whatever_Your_URL_Is'
$http.get(url)
  .then(function(response) 
      $scope.pendingRequests--;
)

【讨论】:

【参考方案27】:

这是我的解决方案,我觉得比其他人在这里发布的解决方案要容易得多。虽然不确定它有多“漂亮”,但它解决了我所有的问题

我有一个叫做“加载”的 CSS 样式

.loading  display: none; 

加载 div 的 html 可以是任何内容,但我使用了一些 FontAwesome 图标和 spin 方法:

<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 将其删除。

【讨论】:

以上是关于在 AngularJS 中的 $http 请求期间显示微调器 GIF?的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 中的跨域 HTTP 请求失败

AJAX 中的 Http POST 请求完美运行,但在 AngularJS 中却不行

错误消息“无法加载 XMLHttpRequest。 AngularJS 中的 HTTP 仅支持跨源请求

angularjs $q$http 处理多个异步请求

TypeScript/angularJS HTTP GET 请求中的范围

两强相争,鹿死谁手 — JQuery中的Ajax与AngularJS中的$http