【问题标题】:Set rootScope variable on httpIntercept在 httpIntercept 上设置 rootScope 变量
【发布时间】:2014-02-01 02:36:27
【问题描述】:

我希望能够设置一个 AngularJS http 拦截器,它将 $rootScope.loading 设置为 truefalse,具体取决于当前是否正在进行 AJAX 请求。

到目前为止,我已将以下内容放在一起:

angular.module('myApp')
.config(function ($httpProvider) {
  $httpProvider.responseInterceptors.push('loadingInterceptor');

  var loadingFunction = function (data, headersGetter) {
      $rootScope.loading = true

      return data;
  };
  $httpProvider.defaults.transformRequest.push(loadingFunction);
})
.factory('loadingInterceptor', function ($q, $window, $rootScope) {
    return function (promise) {
        return promise.then(function (response) {
            $rootScope.loading = false;
            return response;

        }, function (response) {
            $rootScope.loading = false;
            return $q.reject(response);
        });
    };
});

但是我无法将$rootScope 注入到配置块中,因此我无法在HTTP 请求开始时设置$rootScope.loading 变量。

我在这里遗漏了什么吗?我该怎么做?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    responseInterceptors 已被弃用 http://docs.angularjs.org/api/ng.$http。我已经增强了前面的例子:

    app.factory('myHttpInterceptor', ['$q', '$rootScope', '$injector',
        function ($q, $rootScope, $injector) {
            $rootScope.showSpinner = false;
            $rootScope.http = null;
            return {
                'request': function (config) {
                    $rootScope.showSpinner = true;
                    return config || $q.when(config);
                },
                'requestError': function (rejection) {
                    $rootScope.http = $rootScope.http || $injector.get('$http');
                    if ($rootScope.http.pendingRequests.length < 1) {
                        $rootScope.showSpinner = false;
                    }
                    if (canRecover(rejection)) {
                        return responseOrNewPromise
                    }
                    return $q.reject(rejection);
                },
                'response': function (response) {
                    $rootScope.http = $rootScope.http || $injector.get('$http');
                    if ($rootScope.http.pendingRequests.length < 1) {
                        $rootScope.showSpinner = false;
                    }
                    return response || $q.when(response);
                },
                'responseError': function (rejection) {
                    $rootScope.http = $rootScope.http || $injector.get('$http');
                    if ($rootScope.http.pendingRequests.length < 1) {
                        $rootScope.showSpinner = false;
                    }
                    if (canRecover(rejection)) {
                        return responseOrNewPromise
                    }
                    return $q.reject(rejection);
                }
            }
        }
    ]);
    

    你可以像这样使用工厂:

    app.config(function ($httpProvider) {
        $httpProvider.interceptors.push('myHttpInterceptor');
    });
    

    【讨论】:

    • canRecover 未定义 b/c 这应该是您的用例的自定义逻辑(即检查 401 未授权等)
    【解决方案2】:

    您只能在 module.config 中插入提供程序,但无论如何您都不应该在默认转换器中执行此操作,您应该在拦截器中执行此操作(就像您在设置 loading = false 时所做的那样)。

    可能有多个请求同时进行。这样的事情可能会起作用:

    angular.module('myApp')
      .config(function ($httpProvider) {
        $httpProvider.responseInterceptors.push(function ($rootScope) {
          $rootScope.numLoadings = 0;
          $rootScope.loading = false;
          return function (promise) {
            $rootScope.numLoadings++;
            $rootScope.loading = true;
            // make sure the loading screen is visible
            var hide = function (r) {
              if ((--$rootScope.numLoadings)===0){
                //console.log('hide the loading screen');
                $rootScope.loading = false;
              }
              return r;
            };
            return promise.then(hide, hide);
          };
        });
      });
    

    当然你不必将 numLoadings 放在根范围内,我只是为了这个例子把它放在那里:http://plnkr.co/edit/32Mh9UOS3Z4vnOtrH9aR?p=preview

    【讨论】:

      【解决方案3】:

      module.config 仅与提供者打交道,您不应尝试从此处访问 $rootScope。

      另外,我认为没有理由手动计算待处理请求的数量,因为它是由 $http 服务提供的,而且……没有必要两次做同样的工作:)

      咖啡脚本

      angular.module('app.services.networkStatusIndicator', []).config([
      
        '$httpProvider'
      
        ( $httpProvider )->
      
          # Network status indicator
          # ========================
          # Monitor XHTTP requests globally and update UI accordigly.
      
          $http = null
          interceptor = ['$q', '$injector', '$rootScope' , ($q, $injector, $rootScope )->
            success = (response)->
              $http = $http or $injector.get '$http'
              if $http.pendingRequests.length < 1
                $rootScope.networkStatus = 'idle'
              response
      
            error = (response)->
              $http = $http or $injector.get '$http'
              if $http.pendingRequests.length < 1
                $rootScope.networkStatus = 'idle'
              $q.reject response
      
            (promise)->
              $rootScope.networkStatus = 'loading'
              promise.then success, error
          ]
          $httpProvider.responseInterceptors.push interceptor
      ])
      

      Javascript

      angular.module('app.services.networkStatusIndicator', []).config([
        '$httpProvider', function($httpProvider) {
          var $http, interceptor;
          $http = null;
          interceptor = [
            '$q', '$injector', '$rootScope', function($q, $injector, $rootScope) {
              var error, success;
              success = function(response) {
                $http = $http || $injector.get('$http');
                if ($http.pendingRequests.length < 1) {
                  $rootScope.networkStatus = 'idle';
                }
                return response;
              };
              error = function(response) {
                $http = $http || $injector.get('$http');
                if ($http.pendingRequests.length < 1) {
                  $rootScope.networkStatus = 'idle';
                }
                return $q.reject(response);
              };
              return function(promise) {
                $rootScope.networkStatus = 'loading';
                return promise.then(success, error);
              };
            }
          ];
          return $httpProvider.responseInterceptors.push(interceptor);
        }
      ]);
      

      【讨论】:

        猜你喜欢
        • 2015-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-30
        • 1970-01-01
        相关资源
        最近更新 更多