285

$on関数を使用してリスナーを$broadcastイベントに登録しました

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

特定のビジネスルールに基づいて、このリスナーの登録を解除したいと思います。しかし、私の問題は、一度登録すると、登録を解除できないことです。

AngularJSに特定のリスナーの登録を解除する方法はありますか?このイベントの登録を解除する$onのようなメソッドは、$offである可能性があります。したがって、ビジネスロジックに基づいて私は言うことができます

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

そして、誰かが「onViewUpdated」イベントをブロードキャストすると、この関数は呼び出されなくなります。

ありがとう

編集:リスナーを別の関数から登録解除したい。登録する機能ではありません。

4

10 に答える 10

488

返された関数を保存し、それを呼び出してイベントの購読を解除する必要があります。

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

また、ドキュメントを参照してください。

于 2013-02-15T16:16:41.480 に答える
62

ほとんどの返信を見ると、非常に複雑に見えます。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();
});
于 2015-03-31T20:19:28.517 に答える
26

このコードは私のために働きます:

$rootScope.$$listeners.nameOfYourEvent=[];
于 2013-08-21T10:39:30.083 に答える
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);
              }
            }
          }
        }
      }
}());

そして、これがどのように機能するかです:

  function myEvent() {
    alert('test');
  }
  $scope.$on('test', myEvent);
  $scope.$broadcast('test');
  $scope.$off('test', myEvent);
  $scope.$broadcast('test');

そして、これが実際のプランカーです

于 2013-02-15T16:13:47.190 に答える
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);
                    }
                }
            }
        }
});

したがって、関数を$ rootscopeにアタッチすることで、すべてのコントローラーで使用できるようになります。

そして私のコードでは私はやっています

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

ありがとう

編集:これを行うAngularJSの方法は、@ LiviuTの回答にあります!ただし、リスナーを別のスコープで登録解除すると同時に、登録解除関数の参照を保持するためにローカル変数を作成しないようにしたい場合。これは可能な解決策です。

于 2013-02-15T16:24:40.327 に答える
1

@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.)

2つの考え:

  1. これは、1回限りのハンドラーに最適な式です。条件文を削除してselfDestruct、自殺任務が完了したらすぐに実行してください。
  2. 閉じた変数への参照を持っていることを考えると、元のスコープが適切に破棄されてガベージコレクションされるかどうか疑問に思います。それをメモリの問題にするためにも、これらを何百万も使用する必要がありますが、私は興味があります。誰かが何か洞察を持っているなら、共有してください。
于 2014-01-08T04:16:39.340 に答える
1

コンポーネントが削除されたときにリスナーのサブスクライブを解除するためのフックを登録します。

$scope.$on('$destroy', function () {
   delete $rootScope.$$listeners["youreventname"];
});  
于 2019-03-11T21:30:27.097 に答える
1

リスナーを何度もオン/オフする必要がある場合は、booleanパラメーターを使用して関数を作成できます

function switchListen(_switch) {
    if (_switch) {
      $scope.$on("onViewUpdated", this.callMe);
    } else {
      $rootScope.$$listeners.onViewUpdated = [];
    }
}
于 2019-04-11T08:06:21.157 に答える
0

'$on'自体が登録解除のための関数を返します

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

unregister()関数を呼び出して、そのリスナーの登録を解除できます

于 2016-06-13T08:04:22.110 に答える
0

1つの方法は、リスナーを使い終わったら、単にリスナーを破棄することです。

var removeListener = $scope.$on('navBarRight-ready', function () {
        $rootScope.$broadcast('workerProfile-display', $scope.worker)
        removeListener(); //destroy the listener
    })
于 2017-10-19T11:51:29.107 に答える