Как отказаться от подписки на широковещательное событие в angularJS. Как удалить функцию, зарегистрированную через $on
Я зарегистрировал свой прослушиватель для события $broadcast, используя функцию $on
$scope.$on("onViewUpdated", this.callMe);
и я хочу отменить регистрацию этого слушателя на основе определенного бизнес-правила. Но моя проблема в том, что после регистрации я не могу ее зарегистрировать.
Есть ли какой-либо метод в AngularJS для регистрации конкретного слушателя? Такой метод, как $для того, чтобы зарегистрировать это событие, может быть $off. Так что на основе бизнес-логики я могу сказать
$scope.$off("onViewUpdated", this.callMe);
и эта функция перестает вызываться, когда кто-то транслирует событие onViewUpdated.
Спасибо
ИЗМЕНИТЬ:
Я хочу удалить регистратор из другой функции. Не функция, в которой я зарегистрирую ее.
Ответы
Ответ 1
Вам нужно сохранить возвращенную функцию и вызвать ее для отказа от подписки на событие.
var deregisterListener = $scope.$on("onViewUpdated", callMe);
deregisterListener (); // this will deregister that listener
Это находится в исходном коде:) хотя бы в 1.0.4. Я просто опубликую полный код, так как он короткий
/**
* @param {string} name Event name to listen on.
* @param {function(event)} listener Function to call when the event is emitted.
* @returns {function()} Returns a deregistration function for this listener.
*/
$on: function(name, listener) {
var namedListeners = this.$$listeners[name];
if (!namedListeners) {
this.$$listeners[name] = namedListeners = [];
}
namedListeners.push(listener);
return function() {
namedListeners[indexOf(namedListeners, listener)] = null;
};
},
Также см. документы.
Ответ 2
Глядя на большинство ответов, они кажутся чрезмерно сложными. Angular имеет встроенные механизмы для отмены регистрации.
Используйте функцию дерегистрации, возвращенную $on
:
// Register and get a handle to the listener
var listener = $scope.$on('someMessage', function () {
$log.log("Message received");
});
// Unregister
$scope.$on('$destroy', function () {
$log.log("Unregistering listener");
listener();
});
Ответ 3
Этот код работает для меня:
$rootScope.$$listeners.nameOfYourEvent=[];
Ответ 4
РЕДАКТИРОВАТЬ: Правильный способ сделать это в ответе @LiviuT!
Вы всегда можете расширить область Angular, чтобы вы могли удалить такие слушатели следующим образом:
//A little hack to add an $off() method to $scopes.
(function () {
var injector = angular.injector(['ng']),
rootScope = injector.get('$rootScope');
rootScope.constructor.prototype.$off = function(eventName, fn) {
if(this.$$listeners) {
var eventArr = this.$$listeners[eventName];
if(eventArr) {
for(var i = 0; i < eventArr.length; i++) {
if(eventArr[i] === fn) {
eventArr.splice(i, 1);
}
}
}
}
}
}());
И вот как это будет работать:
function myEvent() {
alert('test');
}
$scope.$on('test', myEvent);
$scope.$broadcast('test');
$scope.$off('test', myEvent);
$scope.$broadcast('test');
И вот плункер этого в действии
Ответ 5
После отладки кода я создал свою собственную функцию так же, как ответ "blesh". Так вот что я сделал
MyModule = angular.module('FIT', [])
.run(function ($rootScope) {
// Custom $off function to un-register the listener.
$rootScope.$off = function (name, listener) {
var namedListeners = this.$$listeners[name];
if (namedListeners) {
// Loop through the array of named listeners and remove them from the array.
for (var i = 0; i < namedListeners.length; i++) {
if (namedListeners[i] === listener) {
return namedListeners.splice(i, 1);
}
}
}
}
});
поэтому, присоединяя мою функцию к корневому корню $, теперь она доступна всем моим контроллерам.
и в моем коде я делаю
$scope.$off("onViewUpdated", callMe);
Спасибо
EDIT: способ AngularJS для этого - в ответе @LiviuT! Но если вы хотите отменить регистрацию слушателя в другой области и в то же время хотите избегать создания локальных переменных, чтобы сохранить ссылки на функцию де-регистрации. Это возможное решение.
Ответ 6
Ответ на @LiviuT является удивительным, но, похоже, многие люди задаются вопросом, как повторно получить доступ к функции сбрасывания обработчика из другой области или функции $, если вы хотите уничтожить ее из другого места, кроме того, где она была создана, @Рустем Мусабеков отвечает просто отлично, но не очень идиоматично. (И полагается на то, что должно быть частным элементом реализации, который может меняться в любое время.) И оттуда он просто усложняется...
Я думаю, что легкий ответ здесь заключается в том, чтобы просто передать ссылку на функцию срыва (offCallMeFn
в своем примере) в самом обработчике, а затем вызвать ее на основе некоторого условия; возможно, аргумент, который вы указываете в событии, которое вы передаете, или $emit. Таким образом, хендлеры могут срывать себя, когда захотите, где бы вы ни находились, неся вокруг своих собственных разрушений. Например:
// Creation of our handler:
var tearDownFunc = $rootScope.$on('demo-event', function(event, booleanParam) {
var selfDestruct = tearDownFunc;
if (booleanParam === false) {
console.log('This is the routine handler here. I can do your normal handling-type stuff.')
}
if (booleanParam === true) {
console.log("5... 4... 3... 2... 1...")
selfDestruct();
}
});
// These two functions are purely for demonstration
window.trigger = function(booleanArg) {
$scope.$emit('demo-event', booleanArg);
}
window.check = function() {
// shows us where Angular is stashing our handlers, while they exist
console.log($rootScope.$$listeners['demo-event'])
};
// Interactive Demo:
>> trigger(false);
// "This is the routine handler here. I can do your normal handling-type stuff."
>> check();
// [function] (So, there a handler registered at this point.)
>> trigger(true);
// "5... 4... 3... 2... 1..."
>> check();
// [null] (No more handler.)
>> trigger(false);
// undefined (He dead, Jim.)
Две мысли:
- Это отличная формула для обработчика run-once. Просто оставьте условные обозначения и запустите
selfDestruct
, как только он выполнит свою миссию по самоубийству.
- Интересно, будет ли исходная область когда-либо правильно уничтожена и собрана мусор, учитывая, что вы несете ссылки на закрытые переменные. Вы должны использовать миллион из них, чтобы даже проблема с памятью, но мне любопытно. Если у кого-нибудь есть понимание, пожалуйста, поделитесь.
Ответ 7
'$ on' сам возвращает функцию для отмены регистрации
var unregister= $rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, options) {
alert('state changing');
});
вы можете вызвать функцию unregister(), чтобы отменить регистрацию этого слушателя
Ответ 8
Один из способов - просто уничтожить слушателя, как только вы закончите с ним.
var removeListener = $scope.$on('navBarRight-ready', function () {
$rootScope.$broadcast('workerProfile-display', $scope.worker)
removeListener(); //destroy the listener
})