在http Interceptor中设置rootScope变量

时间:2013-04-30 15:50:03

标签: angularjs

我希望能够设置一个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变量。

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

3 个答案:

答案 0 :(得分:13)

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

答案 1 :(得分:3)

你只能在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

答案 2 :(得分:1)

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

此外,我认为没有理由手动计算挂起请求的数量,因为它是由$http服务提供的,而且......没有必要两次执行相同的工作:)

的CoffeeScript

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