2013-02-15 10 views
246

に$を経て登録された機能を削除する方法

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

と私は特定のビジネス・ルールに基づいて登録解除このリスナーにしたいです。しかし、私の問題は、いったんそれが登録されると、私はそれを登録解除することができないということです。

特定のリスナーを登録解除にAngularJSのいずれかの方法がありますか?このイベントの登録を解除する$ onのようなメソッドは$ offかもしれません。だから、ビジネスロジックに基づいて、私は

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

を言うことができ、この機能は、誰かが「onViewUpdated」イベントをブロードキャストしたときに呼び出されて停止します。

おかげ

EDIT: は、私は別の関数からリスナーを登録解除します。私がそれを登録する関数ではありません。

+18

TLDR; $ scope()は、呼び出されたときに元の登録を解除する関数を返します。 – neaumusic

+1

疑問に思う人には、返された関数は[here](https://docs.angularjs.org/api/ng/type/)に記載されています。 $ rootScope.Scope#$ on) –

答えて

431

あなたがする必要があります返された関数を格納し、イベントからの退会を呼び出す。

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

また、the docsを参照してください。

+0

はい。コードをデバッグした後、すべてのイベントを持ち$ $ off関数を作成した$$リスナー配列があることがわかりました。ありがとう –

+0

提供されている登録解除方法を使用できない実際のユースケースは何ですか?登録解除は、リスナーを作成したスコープにリンクされていない別のスコープで行われますか? –

+0

ええ、私は実際に私の答えを削除しました。なぜなら、人々を混乱させたくないからです。これはこれを行う適切な方法です。 –

10

EDIT:これを行うには正しい方法は、@ LiviuTの答えであります!

あなたはいつもあなたがそうのようなそのようなリスナーを削除できるようにするために角度の範囲を拡張することができます

//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'); 

And here's a plunker of it in action

+0

チャームのように働いた! しかし少し編集しました 私はそれを.runセクションに置きました – aimiliano

+0

このソリューションが大好きです。はるかにクリーンなソリューションを作成します。読みやすくなります。 +1 – Rick

7

コードをデバッグした後、 "blesh"の答えと同じように私自身の関数を作成しました。だからこれは私がやったことです

このように私の機能を$ rootscopeにつけることで、私のすべてのコントローラで利用できるようになります。

と私のコードで私は

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

おかげ

をしています

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

+1

@ LiviuTの答えが100%正しいので、私は実際に私の答えを削除しています。 –

+0

@blesh LiviuTの答えは正確であり、実際には登録解除の方法が提供されていますが、異なる範囲でリスナーの登録を解除する必要があるシナリオではうまく機能しません。これは簡単な選択肢です。 –

+1

これは、他のソリューションと同じフックを提供します。あなたは、破壊関数を含む変数を外部クロージャーに入れたり、グローバルコレクションに入れたりすることもできます。 –

25

このコードは、私の作品:LiviuTの答え@

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

$ rootScope。$$リスナーを参照することは、リスナーのライフサイクルを観察し、それを試すのにも良い方法です。 – XML

+0

シンプルで素晴らしいです。私はその機能の参照を削除したと思う。ではない? –

+25

このソリューションは、$$リスナーメンバーがプライベートと見なされるためお勧めできません。実際に、 '$$'という接頭辞を持つ角度オブジェクトのメンバーは、慣例により非公開です。 – shovavnik

1

は、素晴らしいですが、どのように別の$スコープや機能から再アクセスハンドラのティアダウン機能に不思議の人々の多くを残しているようですあなたがそれが作成された場所以外からそれを破壊したい場合。 @РустемМусабековの答えはちょうど素晴らしいですが、それほど慣用的ではありません。 (そして、いつでも変更できるプライベートな実装の詳細であることに頼っています。)そしてそこから、ちょうどもっと複雑になります...

私は簡単な答えは、ハンドラ自体にティアダウン機能(例では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'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. 閉鎖された変数への参照を持っているので、元のスコープが適切に破棄され、ガベージコレクションされるかどうかは疑問です。メモリの問題でさえも百万を使用しなければなりませんが、私は不思議です。誰かが洞察力を持っている場合は、共有してください。
52

ほとんどの回答を見ると、あまりにも複雑に思えます。 Angularには登録を解除する仕組みが組み込まれています。

deregistration function returned by $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(); 
}); 
+0

これらと同じように、多くの回答がありますが、これはより簡潔です。 –

+7

'$ scope。$ on'は' $ destroy'で手作業で登録を解除する必要がないので、ちょっと誤解を招きます。より良い例は、 '$ rootScope。$ on'を使うことです。 – hgoebl

+2

ベスト・アンサーですが、$ destroy内のリスナーを呼び出す理由がリスナーを殺す理由の詳細については、 –

0

'$に' そのもの登録解除

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

のための関数を返しますが

0

一つの方法があることが、リスナーの登録を解除する登録解除()関数を呼び出すことができますあなたがそれで終わったら、単にリスナーを破壊してください。

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