Как я могу отменить регистрацию вещательного события на корневой каталог в AngularJS?

У меня есть следующее:

angular.module('test')
    .controller('QuestionsStatusController1',
    ['$rootScope', '$scope', '$resource', '$state',
    function ($rootScope, $scope, $resource, $state) {

        $scope.action2 = function() {
            $rootScope.$broadcast('[email protected]');
        }

    }]);

angular.module('test')
   .controller('QuestionsStatusController2',
   ['$rootScope', '$scope', '$resource', '$state',
   function ($rootScope, $scope, $resource, $state) {

    $rootScope.$on('[email protected]', function {
         //write your listener here
    })

   }]);

Я понимаю, что мне нужно отменить регистрацию слушающего события. Может ли кто-нибудь сказать мне, как я могу это сделать/сделать это?

Ответ 1

Если вы не отмените регистрацию события, вы получите утечку памяти, так как функция, которую вы передаете в $on, не будет очищена (поскольку ссылка на нее все еще существует). Что еще более важно, любые переменные, которые ссылаются на ссылки в своей области, также будут пропущены. Это приведет к тому, что ваша функция будет вызвана несколько раз, если ваш контроллер будет создан/уничтожен несколько раз в приложении. К счастью, AngularJS предоставляет несколько полезных методов, чтобы избежать утечек памяти и нежелательного поведения:

  • Метод $on возвращает функцию, которая может быть вызвана для деинсталляции прослушивателя событий. Вы хотите сохранить свою функцию де-регистрации как переменную для последующего использования: var cleanUpFunc = $scope.$on('yourevent', ...); См. Документацию для $on: http://docs.angularjs.org/api/ng.$rootScope.Scope#$on

  • Всякий раз, когда область очистки очищается в Angular (т.е. контроллер уничтожается), в эту область запускается событие $destroy. Вы можете зарегистрироваться на событие $scope $destroy и вызывать cleanUpFunc из этого.

Вы можете связать эти две полезные вещи, чтобы правильно подбирать подписки. Я привел пример этого: http://plnkr.co/edit/HGK9W0VJGip6fhYQQBCg?p=preview. Если вы прокомментируете строку cleanUpFunc();, а затем несколько раз нажмите кнопку переключения и сделайте что-нибудь, вы заметите, что наш обработчик событий вызывается несколько раз, что действительно не требуется.

Теперь, после всего, чтобы ваша конкретная ситуация вела себя правильно, просто измените свой код в QuestionsStatusController2 на следующее:

angular.module('test')
   .controller('QuestionsStatusController2',
   ['$rootScope', '$scope', '$resource', '$state',
   function ($rootScope, $scope, $resource, $state) {

    var cleanUpFunc = $rootScope.$on('[email protected]', function {
         //write your listener here
    });

    $scope.$on('$destroy', function() {
        cleanUpFunc();
    });

   }]);

Вызвав cleanUpFunc() в $destroy, ваш прослушиватель событий для события [email protected] будет не подписан и вы больше не будете пропускать память, когда ваш контроллер будет очищен.

Ответ 2

Зарегистрируйте слушателя на локальном $scope, а не $rootScope, и прослушиватель будет автоматически уничтожен, когда контроллер будет удален.

Итак, опубликуем

// EXAMPLE PUBLISHER
angular.module('test').controller('CtrlPublish', ['$rootScope', '$scope',
function ($rootScope, $scope) {

  $rootScope.$broadcast('topic', 'message');

}]);

И подписаться

// EXAMPLE SUBSCRIBER
angular.module('test').controller('ctrlSubscribe', ['$scope',
function ($scope) {

  $scope.$on('topic', function (event, arg) { 
    $scope.receiver = 'got your ' + arg;
  });

}]);

Plunker

Ответ 3

Вот исходный код о логике дерегистрации. Вы можете сделать:

$rootScope.$on('[email protected]', function () {
    $rootScope.$$listeners['[email protected]'] = [];
})

или вызвать функцию дерегистрации, возвращенную с $on()

var deregistration = $rootScope.$on('[email protected]', function () {
    deregistration();
})

Ответ 4

$scope.$on('saveCancelLeadInfo', function (event, args) {

        if ($scope.$$listenerCount["saveCancelLeadInfo"] > 1) {

            $scope.$$listenerCount["saveCancelLeadInfo"] = 0;

        } });