Ouvintes de eventos
Primeiro, é importante entender que existem dois tipos de "ouvintes de eventos":
Ouvintes de eventos de escopo registrados via $on
:
$scope.$on('anEvent', function (event, data) {
...
});
Manipuladores de eventos anexados a elementos via, por exemplo, on
ou bind
:
element.on('click', function (event) {
...
});
$ scope. $ destroy ()
Quando $scope.$destroy()
é executado, ele remove todos os ouvintes registrados $on
nesse escopo $.
Ele não removerá elementos DOM ou qualquer manipulador de eventos anexado do segundo tipo.
Isso significa que a chamada $scope.$destroy()
manual do exemplo na função de link de uma diretiva não removerá um manipulador anexado por exemplo element.on
, nem o próprio elemento DOM.
element.remove ()
Observe que remove
é um método jqLite (ou um método jQuery se o jQuery for carregado antes do AngularjS) e não estiver disponível em um Objeto de Elemento DOM padrão.
Quando element.remove()
é executado, esse elemento e todos os seus filhos serão removidos do DOM juntos, todos os manipuladores de eventos anexados via, por exemplo element.on
.
Ele vai não destruir a $ âmbito associado ao elemento.
Para torná-lo mais confuso, também há um evento jQuery chamado $destroy
. Às vezes, ao trabalhar com bibliotecas jQuery de terceiros que removem elementos ou se você os remove manualmente, pode ser necessário executar uma limpeza quando isso acontece:
element.on('$destroy', function () {
scope.$destroy();
});
O que fazer quando uma diretiva é "destruída"
Isso depende de como a diretiva é "destruída".
Um caso normal é que uma diretiva é destruída porque ng-view
altera a exibição atual. Quando isso acontece, a ng-view
diretiva destrói o escopo $ associado, interrompe todas as referências ao escopo pai e invoca remove()
o elemento.
Isso significa que, se essa exibição contiver uma diretiva com isso em sua função de link, quando for destruída por ng-view
:
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
Os dois ouvintes de eventos serão removidos automaticamente.
No entanto, é importante observar que o código dentro desses ouvintes ainda pode causar vazamentos de memória, por exemplo, se você atingiu o padrão de vazamento de memória JS comum circular references
.
Mesmo nesse caso normal de uma diretiva ser destruída devido a uma alteração na exibição, há coisas que você pode precisar limpar manualmente.
Por exemplo, se você registrou um ouvinte em $rootScope
:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
Isso é necessário, pois $rootScope
nunca é destruído durante a vida útil do aplicativo.
O mesmo acontece se você estiver usando outra implementação de publicação / publicação que não executa automaticamente a limpeza necessária quando o escopo $ é destruído ou se sua diretiva passa retornos de chamada para serviços.
Outra situação seria cancelar $interval
/ $timeout
:
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
Se sua diretiva anexar manipuladores de eventos a elementos, por exemplo, fora da visualização atual, você também precisará limpá-los manualmente:
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
Estes foram alguns exemplos do que fazer quando as diretivas são "destruídas" pelo Angular, por exemplo, por ng-view
ou ng-if
.
Se você possui diretivas personalizadas que gerenciam o ciclo de vida dos elementos DOM, etc., é claro que ficará mais complexo.