AngularJS Factory $rootScope.$on Cleanup

4.9k views Asked by At

How do I cleanup $rootScope.$on event subscriptions from inside a service?

I have a Factory that is being initialized in different controllers in my AngularJS application, where a $rootScope.$on event subscription is being declared. My problem is, when the controller is destroyed, the event is not cleaned up. I have done reading and found that with controllers and directives you can setup a $watch on $destroy for cleanup, but what about for services? How do you clean up services?

Here's a basic Plunker of my problem: http://plnkr.co/edit/dY3BVW. Click the 'create child' button a bunch of time to initialize a child controller that will initialize a factory with the $rootScope.$on. With the browser console open when you the click 'broadcast', you will see a bunch of event subscriptions being fired, event after the child controllers were destroyed.

Snippet from Plunker:

// setup rootScope on in Factory and create multiple instances
// to show that event subscriptions are not cleaned up
// TODO: how do you cleanup in factory?
app.factory('HelloWorldFactory', function($rootScope) {

  // setup event subscription on initialization
  function HelloWorldFactory() {
    console.log('init helloWorldFactory');

    var rootScopeOn = $rootScope.$on('test', function() {
      console.log('test sub', Math.random());
    });
  }

  return HelloWorldFactory;
});

// child ctrl will init a new factory instance
app.controller('ChildCtrl', function($scope, HelloWorldFactory) {
  $scope.name = 'Child';

  var helloWolrdFactory = new HelloWorldFactory();
});
1

There are 1 answers

2
Pepijn On

You can kill the sentinel before creating the new event. The rootScopeOn variable will stay untouched after creating new controllers, so you can kill it every time you initialize it again.

app.factory('HelloWorldFactory', function($rootScope) {

  var rootScopeOn;

  // setup event subscription on initialization
  function HelloWorldFactory() {
    console.log('init helloWorldFactory');
    if (typeof rootScopeOn === 'function') {
      rootScopeOn();
    }

    rootScopeOn = $rootScope.$on('test', function() {
      console.log('test sub', Math.random());
    });
  }

  return HelloWorldFactory;
});

// child ctrl will init a new factory instance
app.controller('ChildCtrl', function($scope, HelloWorldFactory) {
  $scope.name = 'Child';

  var helloWolrdFactory = new HelloWorldFactory($scope);
});