Melina Melina - 6 months ago 44
AngularJS Question

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

I have the following:

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

}]);


It's my understanding that I need to unregister the listening event. Can someone tell me how I could code / do this?

Answer

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.