Подтвердить что ты не робот

AngularJS директива $destroy

У меня есть установка приложения angular с ng-view. В одном представлении, помимо самого представления, есть также компонент внутри этого представления, который динамически загружается. Этот компонент является директивой, которая по существу компилирует содержимое, чтобы содержимое могло быть дополнительно подключено к другим директивам (что есть). Содержимое внутри этого компонента скомпилировано с помощью $compile(element.contents())(scope);.

В качестве примера:

<ng-view>
  <viewer doc="getDocument()">
  </viewer>
</ng-view>


angular.directive('viewer', ['$compile', '$anchorScroll', function($compile, $anchorScroll) {
  return function(scope, element, attrs) {
    scope.$watch(
      function(scope) {
        var doc = scope.$eval(attrs.doc);
        if (!doc)
          return ""

        return doc.html;
      },
      function(value) {
        element.html(value);
        $compile(element.contents())(scope);
      }
    );
  };
}]);

Моя проблема заключается в том, когда я переключаю маршруты, я по существу переключаю содержимое ng-view или viewer. Проблема, с которой я столкнулась, - это утечка памяти, где в других директивах внутри viewer перехватываются события и не очищаются при изменении маршрута.

Один из таких примеров выглядит следующим образом:

angular.directive('i18n', ['$rootScope', 'LocaleService', function($rootScope, LocaleService) {
  var cleanup;
  return {
    restrict: 'EAC',
    compile: function(element, attrs) {
      var originalText = element.text();
      element.text(LocaleService.getTranslation(originalText, attrs.locale));
      cleanup = $rootScope.$on('locale-changed', function(locale) {
        element.text(LocaleService.getTranslation(originalText, attrs.locale || locale));
      });
    },
    link: function(scope) {
      scope.$on('$destroy', function() {
        console.log("destroy");
        cleanup();
      });
    }
  };
}]);

Как это сделать, чтобы эти события были правильно очищены?

Спасибо.

4b9b3361

Ответ 1

Приведенный вами пример i18n будет работать, если вы когда-либо использовали его только один раз.

Я не думаю, что вы должны выполнять привязку события внутри функции компиляции. Вы можете сделать это внутри функции ссылки:

angular.directive('i18n', ['$rootScope', 'LocaleService', function($rootScope, LocaleService) {
  return {
    restrict: 'EAC',
    link: function(scope, element, attrs) {
      var cleanup;
      var originalText = element.text();
      element.text(LocaleService.getTranslation(originalText, attrs.locale));
      cleanup = $rootScope.$on('locale-changed', function(locale) {
        element.text(LocaleService.getTranslation(originalText, attrs.locale || locale));
      });
      scope.$on('$destroy', function() {
        console.log("destroy");
        cleanup();
      });
    }
  };
}]);

В качестве альтернативы вы можете связать событие с самой дочерней областью и использовать $broadcast на $rootScope для его запуска. Таким образом, событие автоматически будет собираться с мусором при уничтожении области:

angular.directive('i18n', ['$rootScope', 'LocaleService', function($rootScope, LocaleService) {
  return {
    restrict: 'EAC',
    link: function(scope, element, attrs) {
      var originalText = element.text();
      setElText();
      function setElText(locale){
        element.text(LocaleService.getTranslation(originalText, attrs.locale || locale));
      }
      scope.$on('locale-changed', setElText);
    }
  };
}]);

$rootScope.$broadcast('locale-change', 'en-AU');