Отмена привязки eventListener при изменении $ состояния (ui-router) - PullRequest
0 голосов
/ 16 января 2019

Чтобы различные компоненты могли общаться друг с другом, я использую метод $emit в методе service

Сервисный код:

this.triggerSelectedAction = function( actionName )
{
    $rootScope.$emit('action-changed', { actionName: actionName } );
};

this.triggerSelectedProject = function( projectName )
{
    $rootScope.$emit('project-changed', { projectName: projectName } );
};

this.triggerSelectedFile = function( fileName )
{
    $rootScope.$emit('file-changed', { fileName: fileName } );
};

this.subscribe = function( scope, cb )
{
    var eventHandler;
    eventHandler = $rootScope.$on('action-changed', cb);
    eventHandler = $rootScope.$on('project-changed', cb);
    eventHandler = $rootScope.$on('file-changed', cb);

    scope.$on( '$destroy', eventHandler );
};

Теперь давайте предположим, что откуда-то внутри приложения я вызываю myService.triggerSelectedAction('doSomething');, и в это время загружается определенный $state (например, toolsState), чей метод $onInit ожидает этого события.

toolsState Controller $onInit код:

myService.subscribe($scope, function eventOccured(event, data) {
    if ( event.name === "action-changed" )              
        setEnvironment();
});

function setEnvironment() {
    // Attach an event listener to the select element
    document
        .getElementById("design-select")
        .addEventListener("change", projectSelectedEvent);
}

Теперь предположим, что мы меняем состояние и, например, переходим к manageState, который также ожидает того же события и имеет аналогичный код $onInit, за исключением того факта, что он связывает eventListener с другим элементом. .

ControlState Controller $onInit код:

myService.subscribe($scope, function eventOccured(event, data) {
    if ( event.name === "action-changed" )              
        setEnvironment();
});

function setEnvironment() {
    // Attach an event listener to the select element
    document
        .getElementById("manage-select")
        .addEventListener("change", projectSelectedEvent);
}

В этом случае, если событие запускается, все работает как положено, за исключением того, что я получаю TypeError: Cannot read property 'addEventListener' of null в консоли, которая ссылается на строку toolsState Controller с методом addEventListener. Он жалуется, что не может найти элемент с id из design-select из-за изменения состояния.

Мне кажется, что $scope из toolsState, когда состояние изменилось, и поэтому его myService.subscribe() метод все еще работает.

Есть ли способ избавиться от этой ошибки.

1 Ответ

0 голосов
/ 18 января 2019

Всякий раз, когда код передает функцию или объект в API, возникает риск создания ссылок на объекты, которые предотвратят сборку мусора.Это может привести к утечкам памяти.

Метод $on возвращает функцию, которая может использоваться для отсоединения обработчика событий:

this.subscribe = function( scope, cb )
{
    var deRegister = {};
    deRegister.ActionChanged = $rootScope.$on('action-changed', cb);
    deRegister.ProjectChanged = $rootScope.$on('project-changed', cb);
    deRegister.FileChanged = $rootScope.$on('file-changed', cb);

    scope.$on( '$destroy', function() {
        deRegister.ActionChanged();
        deRegister.ProjectChanged();
        deRegister.FileChanged();
        deRegister = null; //release deRegister object
        scope = null;      //release scope reference
        cb = null;         //release callback function reference
    ));
};

В дополнение к отмене регистрации обработчиков событий,Код должен освобождать любые созданные ссылки на объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...