If you have used AngularJS, you probably have at least once used the Scope.$on or Scope.$watch methods, and probably had to dispose of listeners / watchers. Here’s a little trick you may like to do just that in a few lines.

Deregistration functions are awkward

AngularJS’s Scope.$on and Scope.$watch methods return a deregistration function which should be called when you don’t need the callback anymore (e.g. if you were listening on $rootScope from a controller), mainly for performance reasons. Not disposing of listeners will keep the garbage collector from doing its job. For instance, if the fooListener below was to use a variable (say counter ) from a higher context, it wouldn’t be freed from memory. This can lead to a large consumption of RAM, and is especially something to watch for in Single-Page Applications and mobile apps.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27









var deregisterFooListener = $rootScope.$on( 'myFooEvent' , fooListener);

var deregisterBarListener = $rootScope.$on( 'myBarEvent' , barListener);

var deregisterBazListener = $rootScope.$on( 'myBazEvent' , bazListener);





$scope.$on( '$destroy' , deregister);







var counter = 0 ;





function fooListener ( ) {



counter = counter + 1 ;

}



function deregister ( ) {



deregisterFooListener();

deregisterBarListener();

deregisterBazListener();

}



Use an array!

This is OK when you only have one or two listeners to care for, but gets messier the more you have. My humble tip: use an array of deregistration functions which you can loop on and call one by one.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var listeners = [

$rootScope.$on( 'myFooEvent' , fooListener),

$rootScope.$on( 'myBarEvent' , barListener),

$rootScope.$on( 'myBazEvent' , bazListener)

];



$scope.$on( '$destroy' , deregister);



function deregister ( ) {

while (listeners.length) {





listeners.pop()();

}

}



That way you won’t pollute the local scope and you won’t have to come up with awkward variable names such as deregisterStateChangeSuccessListener .

Deregistration as a Service

You don’t want to repeat yourself and copy-paste this deregister function all around the codebase, do you? Enter the deregister service.

1

2

3

4

5

6

7

8

9

10

11

12

angular

.module( 'app.utils' )

.value( 'deregister' , deregister);



function deregister ( listeners ) {

return function deregisterCallback ( ) {



while (listeners.length) {

listeners.pop()();

}

};

}



And then you can simply use it like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17



function MyController ( $scope, deregister ) {

$scope.$on( '$destroy' , deregister([

$rootScope.$on( 'myFooEvent' , fooListener),

$rootScope.$on( 'myBarEvent' , barListener),

$rootScope.$on( 'myBazEvent' , bazListener)

]));





var deregisterEverything = deregister([

$rootScope.$on( 'myFooEvent' , fooListener),

$rootScope.$on( 'myBarEvent' , barListener),

$rootScope.$on( 'myBazEvent' , bazListener)

]);



$scope.$on( '$destroy' , deregisterEverything);

}



Much cleaner, isn’t it?