Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I unregister a broadcast event to rootscope in AngularJS?

Tags:

angularjs

People also ask

What is Rootscope broadcast in AngularJS?

$broadcast is used to broadcast a “global” event which can be caught by any listener of that particular scope. The descendant scopes can catch and handle this event by using $scope.

What is $emit $broadcast and $on in AngularJS?

The difference between $broadcast() and $emit() is that the former sends the event from the current controller to all of its child controllers. That means $broadcast() sends an even downwards from parent to child controllers. The $emit() method, on the other hand, does exactly opposite.

What is the purpose of $destroy method in AngularJS?

$destroy. Broadcasted when a scope and its children are being destroyed. Note that, in AngularJS, there is also a $destroy jQuery event, which can be used to clean up DOM bindings before an element is removed from the DOM.


If you don't un-register the event, you will get a memory leak, as the function you pass to $on will not get cleaned up (as a reference to it still exists). More importantly, any variables that function references in its scope will also be leaked. This will cause your function to get called multiple times if your controller gets created/destroyed multiple times in an application. Fortunately, AngularJS provides a couple of useful methods to avoid memory leaks and unwanted behavior:

  • The $on method returns a function which can be called to un-register the event listener. You will want to save your de-register function as a variable for later use: var cleanUpFunc = $scope.$on('yourevent', ...); See the documentation for $on: http://docs.angularjs.org/api/ng.$rootScope.Scope#$on

  • Whenever a scope gets cleaned up in Angular (i.e. a controller gets destroyed) a $destroy event is fired on that scope. You can register to $scope's $destroy event and call your cleanUpFunc from that.

You can tie these two helpful things together to clean up your subscriptions properly. I put together an example of this: http://plnkr.co/edit/HGK9W0VJGip6fhYQQBCg?p=preview. If you comment out the line cleanUpFunc(); and then hit the toggle and do stuff button a few times, you will notice that our event handler gets called multiple times, which is not really desired.

Now, after all of that, to make your specific situation behave correctly, just change your code in QuestionsStatusController2 to the following:

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();
    });

   }]);

By calling cleanUpFunc() in $destroy, your event listener for the action2@QuestionStatusController1 event will be un-subscribed and you will no longer be leaking memory when your controller gets cleaned up.


Register the listener on the local $scope, not the $rootScope, and the listener will be destroyed automatically when the controller is removed.

So to publish

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

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

}]);

And subscribe

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

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

}]);

Plunker


Here is the source code about the deregistration logic. You can do:

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

or call the deregistration function returned from $on()

var deregistration = $rootScope.$on('action2@QuestionStatusController1', function () {
    deregistration();
})