如何在angularJS中取消订阅广播事件。如何删除通过$on注册的函数

我已经使用$on函数注册了我的监听器到$broadcast事件

$scope.$on("onViewUpdated", this.callMe);

并且我想基于特定的业务规则取消这个侦听器的注册。但我的问题是,一旦注册了,我就无法取消注册。

AngularJS中有什么方法可以取消注册一个特定的监听器吗?像$这样的方法,unregister这个事件,可能是$off。基于商业逻辑,我可以说

 $scope.$off("onViewUpdated", this.callMe);

当有人广播"onViewUpdated"事件时,这个函数停止被调用。

谢谢

< p > 编辑: 我想从另一个函数注销侦听器。

122421 次浏览

编辑:正确的方法是在@ liveut的答案!

你总是可以扩展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');

< a href = " http://plnkr。这是它在行动中的一个活塞

您需要存储返回的函数,并调用它来取消对事件的订阅。

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;
};
},

另外,参见的文档

调试代码后,我创建了自己的函数,就像“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);
}
}
}
}
});

因此,通过将函数附加到$rootscope,现在它对所有控制器都可用。

在我的代码中

$scope.$off("onViewUpdated", callMe);

谢谢

编辑:AngularJS的方法是在@LiviuT的答案!但是如果你想在另一个作用域中注销监听器,同时又不想创建局部变量来保留注销函数的引用。这是一个可能的解决方案。

这段代码为我工作:

$rootScope.$$listeners.nameOfYourEvent=[];

@ livut的答案很棒,但似乎让很多人想知道如何从另一个$范围或函数中重新访问处理程序的拆除函数,如果你想从一个地方而不是它创建的地方销毁它。@Рустем Мусабеков的答案很好用,但不是很地道。(并且依赖于一个私有的实现细节,这个细节随时都可能改变。)从那以后,事情就变得更加复杂了……

我认为这里简单的答案是在处理程序本身中携带一个对拆卸函数(在他的例子中是offCallMeFn)的引用,然后根据某些条件调用它;可能是在$broadcast或$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's a handler registered at this point.)


>> trigger(true);
// "5... 4... 3... 2... 1..."


>> check();
// [null] (No more handler.)


>> trigger(false);
// undefined (He's dead, Jim.)

两个想法:

  1. 对于只运行一次的处理程序来说,这是一个很好的公式。只要放弃条件语句,并在selfDestruct完成自杀任务后立即运行它。
  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();
});

'$on'本身返回取消注册的函数

 var unregister=  $rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, options) {
alert('state changing');
});

您可以调用unregister()函数来注销该侦听器

一种方法是在使用完侦听器后直接销毁侦听器。

var removeListener = $scope.$on('navBarRight-ready', function () {
$rootScope.$broadcast('workerProfile-display', $scope.worker)
removeListener(); //destroy the listener
})

注册一个钩子,当组件被移除时取消订阅监听器:

$scope.$on('$destroy', function () {
delete $rootScope.$$listeners["youreventname"];
});

如果你需要多次打开和关闭监听器,你可以创建一个带有boolean参数的函数

function switchListen(_switch) {
if (_switch) {
$scope.$on("onViewUpdated", this.callMe);
} else {
$rootScope.$$listeners.onViewUpdated = [];
}
}