如何取消订阅angularJS中的广播事件.如何删除通过$ on注册的功能

Hit*_*eja 273 angularjs

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

$scope.$on("onViewUpdated", this.callMe);
Run Code Online (Sandbox Code Playgroud)

我想根据特定的业务规则取消注册此侦听器.但我的问题是,一旦注册,我无法取消注册.

AngularJS中是否有任何方法可以取消注册特定的侦听器?像$ on这样取消注册此事件的方法可能是$ off.所以我可以说基于业务逻辑

 $scope.$off("onViewUpdated", this.callMe);
Run Code Online (Sandbox Code Playgroud)

当有人播放"onViewUpdated"事件时,此函数停止被调用.

谢谢

编辑:我想从另一个函数取消注册监听器.不是我注册它的功能.

Liv*_* T. 471

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

var deregisterListener = $scope.$on("onViewUpdated", callMe);
deregisterListener (); // this will deregister that listener
Run Code Online (Sandbox Code Playgroud)

这可以在源代码:)中找到,至少在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;
    };
},
Run Code Online (Sandbox Code Playgroud)

另外,请参阅文档.

  • @Liviu:随着应用程序的增长,这将成为头痛的问题.不仅是这个事件还有很多其他事件,并且不一定总是在相同的范围函数中取消注册.可能会出现这样的情况,即我正在调用一个正在注册此侦听器但在其他调用上取消注册侦听器的函数,即使在那些情况下我也不会获得引用,除非我将它们存储在我的范围之外.所以对于我目前的实现,我的实现对我来说是可行的解决方 但绝对想知道AngularJS以这种方式做到的原因. (3认同)
  • 我认为 Angular 这样做是因为很多时候内联匿名函数被用作 $on 函数的参数。为了调用 $scope.$off(type, function) 我们需要保留对匿名函数的引用。它只是以一种不同的方式思考人们通常如何在 ActionScript 或 Java 中的 Observable 模式等语言中添加/删除事件侦听器 (2认同)

小智 58

看看大多数回复,它们看起来过于复杂.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();
});
Run Code Online (Sandbox Code Playgroud)

  • 技术上正确,虽然有点误导,因为`$ scope.$ on`不必在`$ destroy`上手动取消注册.一个更好的例子是使用`$ rootScope.$ on`. (8认同)
  • 最好的答案,但希望看到有关为什么在$ destroy内调用该监听器的更多解释会杀死监听器. (2认同)

小智 27

这段代码适合我:

$rootScope.$$listeners.nameOfYourEvent=[];
Run Code Online (Sandbox Code Playgroud)

  • 建议不要使用此解决方案,因为$$侦听器成员被视为私有.事实上,具有'$$'前缀的角对象的任何成员都是按惯例私有的. (25认同)
  • 我不建议使用此选项,因为它会删除所有侦听器,而不仅仅是您需要删除的侦听器.当您在脚本的另一部分中添加另一个侦听器时,它可能会在将来导致问题. (5认同)

Ben*_*esh 10

编辑:正确的方法是@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);
              }
            }
          }
        }
      }
}());
Run Code Online (Sandbox Code Playgroud)

以下是它的工作原理:

  function myEvent() {
    alert('test');
  }
  $scope.$on('test', myEvent);
  $scope.$broadcast('test');
  $scope.$off('test', myEvent);
  $scope.$broadcast('test');
Run Code Online (Sandbox Code Playgroud)

这里有一个实际的吸收者


Hit*_*eja 7

在调试代码之后,我创建了自己的函数,就像"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);
                    }
                }
            }
        }
});
Run Code Online (Sandbox Code Playgroud)

所以通过将我的函数附加到$ rootscope现在它可供我的所有控制器使用.

在我的代码中,我正在做

$scope.$off("onViewUpdated", callMe);
Run Code Online (Sandbox Code Playgroud)

谢谢

编辑:AngularJS的方法是@LiviuT的回答!但是,如果要在另一个范围内取消注册侦听器,同时又希望远离创建局部变量以保留de-registeration函数的引用.这是一种可能的解决方案.