web-dev-qa-db-ja.com

角度付きの$ onと$ broadcast

異なるビューを持つfooterControllerとcodeScannerControllerがあります。

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

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

Footer.htmlの<li>をクリックすると、codeScannerControllerでこのイベントを受け取るはずです。

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

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

269
Alice Polansky

$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
});

これに関するドキュメントは スコープドキュメント の中にあります。

613
Davin Tryon

まず、 $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 - コントローラー1から見た場合$scope、次に$rootScope
  • ブロードキャスト2 - コントローラー2 $scope、次にコントローラー3 $scopeで表示されます
  • 放出2 - コントローラー2から見られます$scopeそして$rootScope
  • ブロードキャスト3 - コントローラー3からのみ表示されます$scope
  • Emit 3 - コントローラー3 $scope、コントローラー2 $scope、そして$rootScopeに見えます
  • ブロードキャストルート - すべてのコントローラの$rootScope$scopeで見られます(1、2、そして3)
  • Emit Root - $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');
    });
}]);
94
th3uiguy

知っておくべき1つのことは、$ prefixはAngular Methodを表し、$$ prefixesは使用しないようにするべき角度メソッドを表します。

以下はテンプレートとそのコントローラの例です。$ 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には、secondCtrlでその名前を識別できるように、一意の名前を付けます。私はブームを選びました!ただ楽しみのために。 2番目の引数 'arguments'により、リスナーに値を渡すことができます。

放送を受信して​​います

2番目のコントローラでは、ブロードキャストを聴くためのコードを設定する必要があります。

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

それは本当にとても簡単です。 ライブ例

同様の結果を得るための他の方法

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

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

最後に、耳を傾けるのに非常に便利なブロードキャストは '$ destroy'です。ここで、$はベンダーコードによって作成されたメソッドまたはオブジェクトです。とにかく$ destroyはコントローラが破壊されたときにブロードキャストされます、あなたはコントローラがいつ削除されたかを知るためにこれを聴くことができます。

26
Yang Li
//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();
       };
    }); }());
1
Sandy