问题
I followed this post to implement a similar ajax loader image on a project:
- Implementing loading spinner using httpInterceptor and AngularJS 1.1.5
My implementation has a few differences:
- I use
$rootScope
toemit
and notbroadcast
and I also use$rootScope
on the directive to handle the event. - Because of a particularity of the project, I have to unbind the directive
$rootScope.$on
listeners right after the first event being fired (either for show or hide), inside the event handler. - I only fire a single show/hide event. Show on the first HTTP request, hide when the count reaches 0.
I believe those are the major differences from the linked post, not sure if they are relevant to my question but just in case they are...
When the loader hide event is handled, the loader is gone and I won't show it again unless the page is refreshed, but I still have background http requests to refresh data on the current page. Those requests will still be intercepted and fire new show/hide events, which are no longer required/handled. I only need a first show and first hide, that's it.
What's the right way to remove the HTTP interceptor I added to the $httpProvider
after the the first hide event has been fired?
I know we add the interceptor using a $httpProvider.interceptors.push()
but I'm not sure how to pop it out when I no longer need that interceptor.
回答1:
I was going to put a bounty on this, as I had the same question. However....it looks as though the interceptors
and responseInterceptors
are simply arrays, according to the source code (lines 127 and 133 in the $httpProvider
factory). There's no wrapper around this.
From what I can tell, you would either have to use pop()
or any other array method. However, this means that you don't know what you're popping! Holding a reference to the object wouldn't really help, because you can't really do an array function on it, unless you decide to iterate based on equality (which could work, using indexOf or something else like Underscore).
Really, what Angular needs is a wrapper for this since you can't be sure that your interceptor is the last one on the list.
回答2:
The best solution that I've found is the one explained by jedd.ahyoung in his comment.
These are the steps.
Add two custom factories
angular.module('myModule.services', [])
/**
* Save application information.
*/
.factory('Application', function($log) {
return {};
})
/**
* Custom Http Interceptor for the loader.
*/
.factory('myHttpInterceptor', function($rootScope, $q, Application) {
return {
request: function(config) {
if(Application.enableLoader){
$rootScope.$broadcast('loading:show');
}
return config;
},
requestError: function(rejection) {
$rootScope.$broadcast('loading:hide');
return $q.reject(rejection);
},
response: function(response) {
$rootScope.$broadcast('loading:hide');
return response;
},
responseError: function(rejection) {
$rootScope.$broadcast('loading:hide');
return $q.reject(rejection);
}
};
});
Add it in your config
step
.config(function($httpProvider) {
//loading interceptor
$httpProvider.interceptors.push('myHttpInterceptor');
});
Enable/disable it when/where you want
Application.enableLoader = true;
$http({
url: url,
method: "GET"
}).success(function(data){
$log.log("Data received and my loader is already closed :)");
Application.enableLoader = false;
$scope.retrieveBooks();
}).error(function(){
$log.log("Error, but my loader is already closed :)");
Application.enableLoader = false;
$scope.retrieveBooks();
});
$scope.retrieveBooks = function(){
$http({
url: url,
method: "GET"
}).success(function(data){
$log.log("Data received and my loader is not closed :(");
}).error(function(){
$log.log("Error, but my loader is not closed :(");
});
};
来源:https://stackoverflow.com/questions/21293650/right-way-to-disable-remove-http-interceptors-in-angular