Очистка интервала при удалении элемента, содержащего угловую директиву

Я создал простую директиву, которая добавляет анимацию загрузки на основе javascript. Он работает с циклом window.setInterval(). Это прекрасно работает, но когда загрузка завершена, я использую ngSwitch для замены своего контента, что удаляет элемент, содержащий атрибут директивы загрузки, со страницы.

В идеале я хотел бы следить за этим изменением и очищать свой интервал, чтобы вычисления анимации не выполнялись в фоновом режиме. Я пробовал смотреть пользовательскую функцию, которая оценивает наличие элемента на странице. Я знаю, что функция работает при обнаружении этого, но кажется, что проблема заключается во времени, а именно, насколько я могу судить, сам $watch очищается, когда элемент атрибута директивы покидает страницу. Поэтому мое выражение $watch никогда не обнаруживает изменений и никогда не вызывает свой обратный вызов, очищающий функцию интервала анимации.

Есть ли рекомендуемая схема действий в подобных ситуациях?

Соответствующий фрагмент из моего шаблона:

<div ng-switch on="dataStatus">

  <div ng-switch-when="loading">
    <div loading-spinner></div>
  </div>

  <div ng-switch-when="haveData">
    <!-- data dependent on content we were loading -->
  </div>

</div>

Упрощенная версия моей директивы:

myModule.directive('loadingSpinner', function () {
  var updateMySweetAnimation = function (element) { /* ... */ };
  return {
    link: function (scope, iElement, iAttrs) {
      var spinner = window.setInterval(function () {
        updateMySweetAnimation(iElement);
      }, 100);

      scope.$watch(function () {
        return $(document).find(iElement).length;
      }, function (present) {
        if (!present) {
          clearInterval(spinner);
        }
      });
    }
  };
});

person cmw    schedule 10.10.2013    source источник


Ответы (1)


Когда элемент удаляется со страницы ng-switch, должны произойти две вещи:

  1. Область, созданная для ng-switch-when, элемента с вашей директивой, уничтожается. Это убивает ваш $watch и генерирует событие $destroy во всей области видимости, которое вы можете наблюдать с помощью scope.$on('$destroy', ...).

  2. Элемент удаляется из DOM. Это генерирует отдельное событие уничтожения, которое вы можете наблюдать с помощью iElement.on('$destroy', ...).

Они должны происходить в этом порядке, глядя на последнюю стабильную версию (1.0.8 — https://github.com/angular/angular.js/blob/v1.0.8/src/ng/directive/ngSwitch)..js), поэтому ваша область действия и, следовательно, ваша watch всегда должен быть мертв, когда элемент удаляется из DOM.

Вы можете избежать этой проблемы, наблюдая из внешней области, где определено ng-switch. Или вы могли бы наблюдать за dataStatus тем же состоянием, что и в вашем ng-switch, вместо того, чтобы искать результаты ng-switch, видя изменение вашего состояния.

Оба они, вероятно, будут работать, но на самом деле все, что вам нужно сделать, и на самом деле нормальный шаблон для этого, это просто наблюдать за одним из событий $destroy и очищать там все. Поскольку интервал кажется более важным для представления, чем для модели, я бы использовал событие DOM и заменил ваш $watch на

iElement.on('$destroy', function(){
    clearInterval(spinner);
});
person Andyrooger    schedule 10.10.2013
comment
Спасибо @Andyrooger, это именно то, что я искал. Поскольку я намереваюсь, чтобы моя директива была многоразовой, я не хочу связывать ее с какими-либо моделями в конкретной родительской области, которую она получает в этом случае, поэтому я настрою обработчик для события DOM. - person cmw; 10.10.2013