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

Aja*_*wal 233 ajax busyindicator angularjs

我正在使用$httpAngularJS 的服务来发出Ajax请求.

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

我没有ajaxstartevent在AngularJS文档中看到类似的东西.

Jos*_*ler 471

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

.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;
  });
});
Run Code Online (Sandbox Code Playgroud)

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

<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>
Run Code Online (Sandbox Code Playgroud)

  • 如果你同时有多个ajax请求,你可以将`loading`声明为一个整数`$ scope.loading = 0;`,当一个请求开始时你做`$ scope.loading ++;`,当它结束时你做`$ scope.loading - ;`.并且模板中没有任何改变.因此,当至少有一个请求正在进行时,将显示微调器,并在其余时间隐藏 (223认同)
  • 您可能也应该在错误回退功能中将加载设置为false. (16认同)
  • 一种更简洁的方法,而不是在成功和失败回调中放置`$ scope.loading = false`,就是把它放在`.finally()`中.它看起来像:`mySvc.get().then(success,fail).finally(function(){$ scope.loading = false;});` (5认同)
  • @sebnukem你是对的.这是一个非常高级的例子,但为了清晰起见,我还是继续添加它.感谢您的反馈! (3认同)

bul*_*ous 88

以下是当前过去的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']).
//.......
Run Code Online (Sandbox Code Playgroud)

这是其余部分(HTML/CSS)....使用

$('#mydiv').show(); 
$('#mydiv').hide(); 
Run Code Online (Sandbox Code Playgroud)

切换它.注意:以上内容用于发布之初的角度模块

#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>
Run Code Online (Sandbox Code Playgroud)

  • 根据AngularJS的最佳实践(被接受的解决方案违反),您不应该在指令之外修改DOM.考虑从指令中调用元素上的show/hide. (38认同)
  • 请注意,您可以使用`angular.element('#mydiv').show()`而不是`$('#mydiv').show()` (19认同)
  • 如果您的页面发出多个ajax请求,这将不起作用.它将在第一个请求结束后隐藏加载gif. (8认同)
  • 我不确定我是否足够评论......但是这样做的正确方法是使用`ng-class`指令而不是使用JQuery来显示和隐藏元素? (7认同)
  • @JamesHeald是正确的..你永远不需要在Angular中使用jQuery进行任何dom操作.请查看:ng-class,ng-if,ng-hide,ng-show等等.对于您将需要的几乎所有内容,都有一个指令. (2认同)

pun*_*lly 44

这是一个使用directive和的版本ng-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');
          }
        });
      }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

通过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');
      });
  };
};
Run Code Online (Sandbox Code Playgroud)

拦截器:

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

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


小智 31

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

对于资源如下:

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

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

<div ng-hide="user.$resolved">Loading ...</div>
Run Code Online (Sandbox Code Playgroud)


edd*_*iec 14

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>
Run Code Online (Sandbox Code Playgroud)


Bal*_*zar 13

刚刚发现了angular-busy一个显示一个小加载器的指令,取决于一些异步调用.

例如,如果你必须做一个GET,请参考你的承诺$scope,

$scope.req = $http.get('http://google.fr');
Run Code Online (Sandbox Code Playgroud)

并称之为:

<div cg-busy="req"></div>
Run Code Online (Sandbox Code Playgroud)

这是GitHub.

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

bower install angular-busy --save
Run Code Online (Sandbox Code Playgroud)


小智 5

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

ng-show="angular.isUndefined(scope.data.someObject)".
Run Code Online (Sandbox Code Playgroud)

在这里,尽管someObject未定义,微调器将显示。服务返回数据并someObject填充后,微调框将返回其隐藏状态。


drz*_*aus 5

如果你在服务/工厂内包装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;
    });
Run Code Online (Sandbox Code Playgroud)

SPINNER DIRECTIVE

(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);
Run Code Online (Sandbox Code Playgroud)

用法

<div ng-controller="myCtrl" your-api-spinner> ... </div>
Run Code Online (Sandbox Code Playgroud)