我希望能够设置一个AngularJS http拦截器,它将$rootScope.loading
设置为true
或false
,具体取决于当前是否正在进行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
变量。
我在这里遗漏了什么吗?我该怎么做?
答案 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
服务提供的,而且......没有必要两次执行相同的工作:)
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
])
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);
}
]);