core
core

Reputation: 33059

Deregistration of event handlers in Angular

I saw a piece of code in a controller recently that went something like:

.controller('foobar', ['$scope', '$rootScope', function($scope, $rootScope) {
    var eventHandler = $rootScope.$on('some-event', function() {
        ...
    });

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

Questions:

  1. Is executing the eventHandler "deregistration" function on $scope's $destroy event necessary?
  2. If yes, would executing the deregistration function on $scope's $destroy event have been necessary if 'some-event' was $on $scope instead of $rootScope?
  3. How do I know when I need to execute a deregistration function? I understand detaching or unbinding events is common for cleanup in JavaScript, but what rules can I follow to know when to do this in Angular?

Any advice about understanding this snippet/"deregistration" would be much appreciated.

Upvotes: 1

Views: 2167

Answers (2)

Cathal
Cathal

Reputation: 1790

In the example above the destroy method is necessary. The listener is bound to the $rootscope which means that even after the controller gets $destroy-ed the listener is still attached to the dom through the $rootscope. Every time the controller is instantiated a new eventhandler will be created so without the destroy method you will have a memory leak.

However if you bind the listener to the controllers $scope it will get destroyed along with the controller as the $scope gets destroyed so the listener has no connection to the dom thus making it eligible for garbage collection

Upvotes: 4

Esteban Felix
Esteban Felix

Reputation: 1561

  1. Event handlers are only deregistered on controller's $destroy event when it is on that controller's $scope.
  2. The deregistering would be unnecessary if it's on $scope since that's handled for you by Angular.
  3. Generally if it's not tied to instance of the individual element, controller, or service you are listening on then that is when you need to handle deregistering yourself.

A good example is a directive that registers event listeners on the $document:

var module = angular.module('test', []);
module.directive('onDocumentClick', function directiveFactory($document) {
    return {
        link: function (scope, element, attrs) {
            var onDocumentClick = function () {
                console.log('document clicked')
            };

            $document.on('click', onDocumentClick);

            // we need to deregister onDocumentClick because the event listener is on the $document not the directive's element
            element.on('$destroy', function () {
                $document.off('click', onDocumentClick);
            });
        }
    };
});

Upvotes: 1

Related Questions