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();
});
}
};
}]);
Как это сделать, чтобы эти события были правильно очищены?
Спасибо.
Ответы
Ответ 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');