$ onおよび$ broadcast in angular


282

私は異なるビューを持つフッターコントローラーとコードスキャナーコントローラーを持っています。

angular.module('myApp').controller('footerController', ["$scope", function($scope) {}]);

angular.module('myApp').controller('codeScannerController', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...

<li>footer.html内のをクリックすると、codeScannerControllerでこのイベントを取得する必要があります。

<li class="button" ng-click="startScanner()">3</li>

私はそれがで実現することができると思う$on$broadcast、私は方法がわからないとどこにも例を見つけることができません。

回答:


631

あなたが$broadcast使用したい場合$rootScope

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}

そして、受信するに$scopeは、コントローラのを使用します。

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});

必要な場合は、次のときに引数を渡すことができます$broadcast

$rootScope.$broadcast('scanner-started', { any: {} });

そしてそれらを受け取ります:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});

Scope docs内のこれに関するドキュメント


2
イベントには好きな名前を付けることができます。
Davin Tryon 2013年

5
$ scope。$ apply();であることを確認してください。あなたの変化!
Ismail

4
@Ismailなぜ...そしてどこに?
Jaans 2014

7
ブロードキャストメッセージをハードコーディングするのではなく、これらの文字列をどこかに保存するための推奨される方法はありますか?
rperryng 2014

8
@Ismail $scope.$apply()は、角度のフレームワークの外部でモデルを変更する場合(setTimeout、ダイアログコールバック、またはajaxコールバックなど)にのみ必要です。つまり$apply()、すべてのコード.$on()が終了した後ですでにトリガーされています。
th3uiguy

97

まず、の簡単な説明$on()$broadcast()および$emit()

  • .$on(name, listener) -指定された特定のイベントをリッスンします name
  • .$broadcast(name, args)- $scopeすべての子供たちを通してイベントを放送します
  • .$emit(name, args)- $scopeを含むすべての親にイベントを送信します。$rootScope

次のHTMLに基づいています(ここで完全な例を参照):

<div ng-controller="Controller1">
    <button ng-click="broadcast()">Broadcast 1</button>
    <button ng-click="emit()">Emit 1</button>
</div>

<div ng-controller="Controller2">
    <button ng-click="broadcast()">Broadcast 2</button>
    <button ng-click="emit()">Emit 2</button>
    <div ng-controller="Controller3">
        <button ng-click="broadcast()">Broadcast 3</button>
        <button ng-click="emit()">Emit 3</button>
        <br>
        <button ng-click="broadcastRoot()">Broadcast Root</button>
        <button ng-click="emitRoot()">Emit Root</button>
    </div>
</div>

発生したイベントは$scopes次のようにトラバースします。

  • ブロードキャスト1-コントローラー1でのみ表示されます $scope
  • 放出1- $scope次にコントローラー1に表示されます$rootScope
  • ブロードキャスト2-コントローラー2 $scopeからコントローラー3に表示されます$scope
  • EMIT 2 -コントローラ2で見られます$scopeその後、$rootScope
  • ブロードキャスト3-コントローラー3でのみ表示されます $scope
  • 放出3-コントローラ3に表示され$scope$scope次にコントローラ2に表示されます。$rootScope
  • ブロードキャストルートは-によって理解されるであろう$rootScope$scope(3後、2、1)すべてのコントローラ
  • ルートを放出-のみに表示されます $rootScope

イベントをトリガーするJavaScript(ここでも実際の例をここに示します):

app.controller('Controller1', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.broadcastAndEmit = function(){
        // This will be seen by Controller 1 $scope and all children $scopes 
        $scope.$broadcast('eventX', {data: '$scope.broadcast'});

        // Because this event is fired as an emit (goes up) on the $rootScope,
        // only the $rootScope will see it
        $rootScope.$emit('eventX', {data: '$rootScope.emit'});
    };
    $scope.emit = function(){
        // Controller 1 $scope, and all parent $scopes (including $rootScope) 
        // will see this event
        $scope.$emit('eventX', {data: '$scope.emit'});
    };

    $scope.$on('eventX', function(ev, args){
        console.log('eventX found on Controller1 $scope');
    });
    $rootScope.$on('eventX', function(ev, args){
        console.log('eventX found on $rootScope');
    });
}]);

あなたが与えた例で私のアプリの階層をどのように想像できますか?コントローラはどのようにして親または子にすることができますか?私が言おうとしているのは、私には一連の状態があるということです。LoginCtrl-> homeCrl-> notificationCtrlなど。
HIRA THAKUR

26

知っておくべきことの1つは、$プレフィックスがAngularメソッドを指し、$$プレフィックスが使用を避けるべきAngularメソッドを指すことです。

以下は、テンプレートとそのコントローラーの例です。$ broadcast / $ onを使用して、目的を達成する方法を説明します。

<div ng-controller="FirstCtrl">
    <input ng-model="name"/> 
    <button ng-click="register()">Register </button>
</div>

<div ng-controller="SecondCtrl">
    Registered Name: <input ng-model="name"/> 
</div>

コントローラは

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});

私への質問は、ユーザーが登録をクリックしたときに、2番目のコントローラーに名前をどのように渡すのですか?複数のソリューションを考え出すかもしれませんが、ここで使用するのは$ broadcastと$ onを使用することです。

$ broadcast対$ emit

どちらを使用すればよいですか?$ broadcastはすべての子dom要素にチャネリングし、$ emitはすべての先祖dom要素に逆方向をチャネリングします。

$ emitと$ broadcastのどちらかを決定しないようにする最良の方法は、$ rootScopeからチャネルを作成し、そのすべての子に$ broadcastを使用することです。これは、dom要素が兄弟であるため、ケースがはるかに簡単になります。

$ rootScopeを追加して$ broadcastを許可する

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});

$ rootScopeを追加し、今では$ broadcast(broadcastName、arguments)を使用していることに注意してください。broadcastNameについては、2番目のCtrlでその名前をキャッチできるように、一意の名前を付けます。私はブームを選びました!楽しみのためだけに。2番目の引数「引数」を使用すると、リスナーに値を渡すことができます。

放送を受け取る

2番目のコントローラーでは、ブロードキャストをリッスンするようにコードを設定する必要があります

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});

とても簡単です。実例

同様の結果を達成する他の方法

この一連のメソッドは、効率的でも保守も容易ではないため、使用しないようにしてください。ただし、これは、発生する可能性のある問題を修正する簡単な方法です。

通常、サービスを使用するか、コントローラーを簡略化することで、同じことを実行できます。これについては詳しく説明しませんが、完全を期すために触れておきます。

最後に、聞くのに本当に役立つブロードキャストは「$ destroy」です。$は、ベンダーコードによって作成されたメソッドまたはオブジェクトであることを意味します。とにかく、$ destroyはコントローラーが破壊されたときにブロードキャストされます。コントローラーが削除されたことを知るためにこれを聞くことができます。


2
警告として、アプリでブロードキャスト/エミットを使いすぎないようにしてください。これらのイベントのルーツを追跡することは非常に困難な作業であるため、特に大きなアプリでは、それらを管理するのが非常に難しい場合があります。
ヤン李

1
//Your broadcast in service

(function () { 
    angular.module('appModule').factory('AppService', function ($rootScope, $timeout) {

    function refreshData() {  
        $timeout(function() {         
            $rootScope.$broadcast('refreshData');
        }, 0, true);      
    }

    return {           
        RefreshData: refreshData
    };
}); }());

//Controller Implementation
 (function () {
    angular.module('appModule').controller('AppController', function ($rootScope, $scope, $timeout, AppService) {            

       //Removes Listeners before adding them 
       //This line will solve the problem for multiple broadcast call                             
       $scope.$$listeners['refreshData'] = [];

       $scope.$on('refreshData', function() {                                                    
          $scope.showData();             
       });

       $scope.onSaveDataComplete = function() { 
         AppService.RefreshData();
       };
    }); }());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.