7

我希望能够设置一个 AngularJS http 拦截器,该拦截器将设置$rootScope.loadingtruefalse,具体取决于当前是否正在进行 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配置块,所以$rootScope.loading当 HTTP 请求开始时我无法设置变量。

我在这里错过了什么吗?我该怎么做?

4

3 回答 3

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');
});
于 2013-09-20T13:28:04.453 回答
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

于 2013-05-01T06:43:13.820 回答
1

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);
  }
]);
于 2013-09-17T10:03:11.650 回答