Pregunta

I followed this post to implement a similar ajax loader image on a project:

My implementation has a few differences:

  • I use $rootScope to emit and not broadcast 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.

¿Fue útil?

Solución

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.

Otros consejos

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 :(");
  });
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top