Фабрика AngularJS $rootScope.$ при очистке

Как очистить подписки на события $rootScope.$on из службы?

У меня есть Factory, которая инициализируется в разных контроллерах в моем приложении AngularJS, где объявляется подписка на событие $rootScope.$on. Моя проблема в том, что когда контроллер уничтожается, событие не очищается. Я прочитал и обнаружил, что с помощью контроллеров и директив вы можете настроить $watch на $destroy для очистки, но как насчет сервисов? Как вы чистите сервисы?

Вот базовый планкер моей проблемы: http://plnkr.co/edit/dY3BVW. Нажмите кнопку «Создать дочерний элемент» несколько раз, чтобы инициализировать дочерний контроллер, который инициализирует фабрику с $rootScope.$on. Когда консоль браузера открыта, когда вы нажимаете «транслировать», вы увидите, как запускается множество подписок на события, событие после того, как дочерние контроллеры были уничтожены.

Фрагмент из плункера:

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

person user12121234    schedule 12.11.2014    source источник
comment
Также хотелось бы знать, что оставшиеся прослушиватели событий могут вызывать действительно неприятное поведение.   -  person twDuke    schedule 13.08.2015
comment
@twDuke Я в основном обернул событие подписки $on в логическое условное выражение, а затем инициализировал его только один раз, установив для переменной isLoaded значение true при первом проходе.   -  person user12121234    schedule 13.08.2015


Ответы (1)


Вы можете убить стража перед созданием нового события. Переменная rootScopeOn останется нетронутой после создания новых контроллеров, поэтому вы можете уничтожать ее каждый раз, когда вы снова инициализируете ее.

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);
});
person Pepijn    schedule 12.11.2014
comment
Это в правильном направлении, однако у меня есть несколько контроллеров, и каждый из них инициализирует свой собственный экземпляр Factory. Таким образом, имея только одну переменную rootScopeOn и несколько экземпляров для управления, он работает над собой и удаляет все, кроме последней инициализированной фабрики. - person user12121234; 12.11.2014
comment
Я изменил Plunker, чтобы сделать это более понятным. Кроме того, чтобы еще больше запутать меня, эта служба на самом деле вызывается из прототипа класса обслуживания модели, унаследованного от разных дочерних классов моделей, и поэтому различать их на родительском уровне, где вызывается фабрика, может быть сложно. - person user12121234; 12.11.2014