Правильный способ отключить/удалить http-перехватчики в Angular?

Я следил за этим сообщением, чтобы реализовать аналогичное изображение загрузчика ajax в проекте:

У моей реализации есть несколько отличий:

  • Я использую $rootScope to emit, а не broadcast, а также я использую $rootScope в директиве для обработки события.
  • Из-за специфики проекта мне нужно отпереть директиву $rootScope.$on слушателей сразу после первого события, которое запускается (либо для показа, либо скрывается) внутри обработчика событий.
  • Я запускаю только событие show/hide. Показывать по первому запросу HTTP, скрыть, когда счетчик достигнет 0.

Я считаю, что это основные отличия от связанного сообщения, не уверен, что они имеют отношение к моему вопросу, но на всякий случай...

Когда обрабатывается событие loader hide, загрузчик пропал, и я не буду показывать его снова, если страница не обновлена, но у меня все еще есть фоновые http-запросы для обновления данных на текущей странице. Эти запросы будут по-прежнему перехватываться и запускать новые события show/hide, которые больше не требуются/обрабатываются. Мне нужно только первое шоу и сначала скрыть, что он.

Какой правильный способ удалить HTTP-перехватчик, который я добавил в $httpProvider после первого события hide?

Я знаю, что мы добавляем перехватчик с помощью $httpProvider.interceptors.push(), но я не уверен, как его вытащить, когда мне больше не нужен этот перехватчик.

Ответ 1

Я собирался поставить щедрость на это, поскольку у меня был тот же вопрос. Однако.... похоже, что interceptors и responseInterceptors являются просто массивами, в соответствии с исходным кодом (строки 127 и 133 в $httpProvider factory). Там нет обертки.

Из того, что я могу сказать, вам придется либо использовать pop(), либо любой другой метод массива. Однако это означает, что вы не знаете, что вы говорите! Сохранение ссылки на объект не помогло бы, потому что вы не можете действительно выполнять функцию массива на нем, если вы не решите итерацию на основе равенства (которое может работать, используя indexOf или что-то еще, например Underscore).

Действительно, для чего нужен Angular, это оболочка, так как вы не можете быть уверены, что ваш перехватчик является последним в списке.

Ответ 2

Лучшим решением, которое я нашел, является тот, который объясняется jedd.ahyoung в его комментарии.

Это шаги.

Добавьте два настраиваемых фабрики

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

Добавьте его на шаге config

.config(function($httpProvider) {
    //loading interceptor
    $httpProvider.interceptors.push('myHttpInterceptor');
});

Включить/отключить его, когда/где вы хотите

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 :(");
  });
};