web-dev-qa-db-fra.com

Comment désinscrire un événement de diffusion sur rootscope dans AngularJS?

J'ai le suivant:

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

        $scope.action2 = function() {
            $rootScope.$broadcast('action2@QuestionStatusController1');
        }

    }]);

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

    $rootScope.$on('action2@QuestionStatusController1', function {
         //write your listener here
    })

   }]);

Je crois comprendre que je dois désenregistrer l'événement d'écoute. Quelqu'un peut-il me dire comment je pourrais coder/faire ceci?

64
user1943020

Si vous ne désenregistrez pas l'événement, vous obtiendrez une fuite de mémoire car la fonction passée à $on ne sera pas nettoyée (car sa référence existe toujours). Plus important encore, toute variable dont la fonction fait référence à des références sera également divulguée. Ainsi, votre fonction sera appelée plusieurs fois si votre contrôleur est créé/détruit plusieurs fois dans une application. Heureusement, AngularJS fournit plusieurs méthodes utiles pour éviter les fuites de mémoire et les comportements indésirables:

  • La méthode $on renvoie une fonction qui peut être appelée pour annuler l'enregistrement de l'écouteur d'événements. Vous souhaitez enregistrer votre fonction de désenregistrement en tant que variable pour une utilisation ultérieure: var cleanUpFunc = $scope.$on('yourevent', ...); Voir la documentation pour $on: http://docs.angularjs.org/api/ng.$rootScope.Scope#$on

  • Chaque fois qu'une étendue est nettoyée dans Angular (c'est-à-dire qu'un contrôleur est détruit), un événement $destroy est déclenché sur cette étendue. Vous pouvez vous inscrire à l'événement $scope de $destroy et appeler votre cleanUpFunc à partir de celui-ci.

Vous pouvez lier ces deux éléments utiles pour nettoyer correctement vos abonnements. J'ai rassemblé un exemple de ceci: http://plnkr.co/edit/HGK9W0VJGip6fhYQQBCg?p=preview . Si vous commentez la ligne cleanUpFunc();, puis que vous appuyez à plusieurs reprises sur le bouton bascule-écran, vous remarquerez que notre gestionnaire d'événements est appelé plusieurs fois, ce qui n'est pas vraiment souhaitable.

Maintenant, après tout cela, pour que votre situation spécifique se comporte correctement, modifiez votre code dans QuestionsStatusController2 comme suit:

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

    var cleanUpFunc = $rootScope.$on('action2@QuestionStatusController1', function {
         //write your listener here
    });

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

   }]);

En appelant cleanUpFunc() dans $destroy, votre écouteur d'événements pour l'événement action2@QuestionStatusController1 ne sera plus abonné et vous ne perdrez plus de mémoire lorsque votre contrôleur est nettoyé.

148
Polaris878

Enregistrez l'écouteur sur le $scope local, et non sur le $rootScope, et l'écouteur sera automatiquement détruit lorsque le contrôleur sera supprimé.

Donc pour publier

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

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

}]);

Et abonnez-vous

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

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

}]);

Plunker

41
poshest

Voici le code source relatif à la logique de désenregistrement. Tu peux faire:

$rootScope.$on('action2@QuestionStatusController1', function () {
    $rootScope.$$listeners['action2@QuestionStatusController1'] = [];
})

ou appelez la fonction de désenregistrement renvoyée par $on()

var deregistration = $rootScope.$on('action2@QuestionStatusController1', function () {
    deregistration();
})
15
zsong
$scope.$on('saveCancelLeadInfo', function (event, args) {

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

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

        } });
0
Shaik Subhani