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

如何取消订阅angularJS中的广播活动。如何删除通过$on注册的函数,angularjs,Angularjs,我已使用$on函数将侦听器注册到$broadcast事件 $scope.$on("onViewUpdated", this.callMe); 我想根据特定的业务规则取消注册此侦听器。但我的问题是,一旦注册,我就无法取消注册 AngularJS中是否有任何方法可以取消注册特定的侦听器?取消注册此事件的方法(如$on)可能是$off。因此,基于业务逻辑,我可以说 $scope.$off("onViewUpdated", this.callMe); 当有人广播“onViewUpdated”事件时

我已使用$on函数将侦听器注册到$broadcast事件

$scope.$on("onViewUpdated", this.callMe);
我想根据特定的业务规则取消注册此侦听器。但我的问题是,一旦注册,我就无法取消注册

AngularJS中是否有任何方法可以取消注册特定的侦听器?取消注册此事件的方法(如$on)可能是$off。因此,基于业务逻辑,我可以说

 $scope.$off("onViewUpdated", this.callMe);
当有人广播“onViewUpdated”事件时,此函数将停止调用

谢谢

编辑
我想从另一个函数中注销侦听器。不是我注册它的函数。

编辑:正确的方法是在@LiviuT的答案中

您始终可以扩展Angular的作用域,以便删除此类侦听器,如下所示:

//在$scopes中添加$off()方法的小技巧。
(功能(){
var注入器=角度注入器(['ng']),
rootScope=injector.get(“$rootScope”);
rootScope.constructor.prototype.$off=function(eventName,fn){
if(此$$listeners){
var eventArr=this.$$listeners[eventName];
if(eventArr){
对于(变量i=0;i
下面是它的工作原理:

函数myEvent(){
警报(“测试”);
}
$scope.$on('test',myEvent);
$scope.$broadcast('test');
$scope.$off('test',myEvent);
$scope.$broadcast('test');

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

var-deregisterListener=$scope.$on(“onViewUpdated”,callMe);
注销侦听器();//这将注销该侦听器
这可以在源代码中找到:)至少在1.0.4中。我会发布完整的代码,因为它很短

/**
*@param{string}name要侦听的事件名称。
*@param{function(event)}在发出事件时调用的侦听器函数。
*@returns{function()}返回此侦听器的注销函数。
*/
$on:函数(名称、侦听器){
var namedListeners=this.$$listeners[name];
如果(!namedListeners){
这是$$listeners[name]=namedListeners=[];
}
namedListeners.push(侦听器);
返回函数(){
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);
                    }
                }
            }
        }
});
谢谢


EDIT:AngularJS的方法是@LiviuT的答案!但是,如果您想在另一个作用域中取消注册侦听器,同时又不想创建局部变量来保留取消注册函数的引用,那么就可以使用。这是一个可能的解决方案。

此代码适用于我:

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

@LiviuT的答案非常棒,但似乎让很多人想知道,如果您想从创建位置以外的其他位置销毁处理程序的分解函数,如何从另一个$scope或函数重新访问该处理程序的分解函数@цццбббббббббббббб。(并且依赖于什么应该是私有的实现细节,它可以随时改变。)从那以后,它就变得更复杂了

我认为这里最简单的答案是简单地在处理程序本身中携带对下拉函数的引用(
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.)
两个想法:

  • 对于一次运行处理程序来说,这是一个很好的公式。只要去掉条件,在完成自杀任务后立即运行自毁
  • 我想知道,如果您携带对closured变量的引用,是否会正确地销毁和垃圾收集原始作用域。你必须使用一百万个这样的东西,甚至是一个记忆问题,但我很好奇。如果有人有任何见解,请分享

  • 从大多数回复来看,它们似乎过于复杂。Angular内置了注销机制

    使用:


    “$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 = [];
        }
    }
    

    对调试sorce代码后,我发现有一个$$listeners数组包含所有事件,并创建了我的$off函数。谢谢,您不能使用提供的取消注册方式的实际用例是什么?在另一个作用域中取消注册是否与创建侦听器的作用域没有链接?是的,我实际上删除了我的答案,因为我不想让人混淆。这是正确的方法。@Liviu:随着应用的增加,这将成为一个令人头痛的问题。不仅仅是这个事件,还有很多其他事件,我不一定总是在同一个作用域函数中取消注册。在某些情况下,我调用的函数正在注册此侦听器,但在其他调用中取消注册侦听器,即使在这些情况下,我也无法获得引用,除非我将它们存储在我的范围之外。因此,对于我当前的实现,我的实现看起来是可行的解决方案。但是我很想知道AngularJS这样做的原因。我认为AngularJS是这样做的
    $scope.$on('$destroy', function () {
       delete $rootScope.$$listeners["youreventname"];
    });  
    
    function switchListen(_switch) {
        if (_switch) {
          $scope.$on("onViewUpdated", this.callMe);
        } else {
          $rootScope.$$listeners.onViewUpdated = [];
        }
    }