web-dev-qa-db-ja.com

$ scope。$ emitと$ scope。$ onを使って作業する

$scopeおよび.$emitメソッドを使用して、.$onオブジェクトをあるコントローラーから別のコントローラーに送信する方法を教えてください。

function firstCtrl($scope) {
    $scope.$emit('someEvent', [1,2,3]);
}

function secondCtrl($scope) {
    $scope.$on('someEvent', function(mass) { console.log(mass); });
}

それは私がそれがあるべきだと思う方法ではうまくいきません。 $emit$onはどのように機能しますか?

869
Paul Kononenko

まず第一に、親子スコープの関係が重要です。イベントを発行するには2つの方法があります。

  • $broadcast - イベントをすべての子スコープに向けて下方にディスパッチします。
  • $emit - スコープ階層を通してイベントを上方にディスパッチします。

私はあなたのコントローラ(スコープ)の関係については何も知りませんが、いくつかの選択肢があります:

  1. firstCtrlのスコープがsecondCtrlスコープの親である場合、コードはfirstCtrl内で$emit$broadcastに置き換えることによって機能するはずです。

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
    
  2. スコープ間に親子関係がない場合は、コントローラに$rootScopeを挿入し、すべての子スコープ(つまりsecondCtrl)にイベントをブロードキャストできます。

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  3. 最後に、子コントローラからスコープにイベントを上向きにディスパッチする必要があるときは、$scope.$emitを使用できます。 firstCtrlのスコープがsecondCtrlスコープの親である場合:

    function firstCtrl($scope)
    {
        $scope.$on('someEvent', function(event, data) { console.log(data); });
    }
    
    function secondCtrl($scope)
    {
        $scope.$emit('someEvent', [1,2,3]);
    }
    
1484
zbynour

私は@zbynourによる提案された選択肢に代わるより良い選択肢として4番目の選択肢をさらに提案するでしょう。

送信側コントローラと受信側コントローラの関係に関係なく、$rootScope.$emitではなく$rootScope.$broadcastを使用してください。そうすることで、イベントは$rootScope.$$listenersのセット内に留まりますが、$rootScope.$broadcastを使うとイベントはすべての子スコープに伝播します。そのほとんどはおそらくそのイベントのリスナーではないでしょう。そしてもちろん受信側のコントローラの最後では$rootScope.$onを使うだけです。

このオプションでは、コントローラのrootScopeリスナーを破棄することを忘れないでください。

var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
  unbindEventHandler();
});
145
Thalis K.

。$ emitメソッドと。$ onメソッドを使用して、$ scopeオブジェクトをあるコントローラから別のコントローラに送信する方法を教えてください。

$ scopeなど、アプリの階層内で必要な任意のオブジェクトを送信できます。

これはブロードキャストがどのように動作するかについての簡単なアイデアです。

以下のノードに注目してください。このシナリオでは、broadcastおよびemitを使用します。

注:この例の各ノードの数は任意です。それは簡単に一番です。ナンバー2。あるいは1,348という数字さえあります。各番号は、この例の単なる識別子です。この例のポイントは、Angular controllers/directiveのネストを示すことです。

                 3
           ------------
           |          |
         -----     ------
         1   |     2    |
      ---   ---   ---  ---
      | |   | |   | |  | |

この木をチェックしてください。次の質問にどう答えますか。

注:これらの質問に答える方法は他にもありますが、ここではブロードキャストおよびについて説明します。 を発行します。また、以下のテキストを読むとき、それぞれの番号がそれ自身のファイル(ディレクティブ、コントローラー)を持っていると仮定します。 one.js、two.js、three.js。

ノード1はノード3とどのように対話しますか?

ファイル内one.js

scope.$emit('messageOne', someValue(s));

ファイル内three.js - 通信に必要なすべての子ノードの最上位ノード。

scope.$on('messageOne', someValue(s));

ノード2はノード3とどのように話しますか。

ファイル内two.js

scope.$emit('messageTwo', someValue(s));

ファイル内three.js - 通信に必要なすべての子ノードの最上位ノード。

scope.$on('messageTwo', someValue(s));

ノード3はノード1および/またはノード2とどのように会話しますか?

ファイル内three.js - 通信に必要なすべての子ノードの最上位ノード。

scope.$broadcast('messageThree', someValue(s));

Fileone.js&&two.jsどちらのファイルをメッセージをキャッチしたいか、またはその両方。

scope.$on('messageThree', someValue(s));

ノード2はノード1とどのように会話しますか?

ファイル内two.js

scope.$emit('messageTwo', someValue(s));

ファイル内three.js - 通信に必要なすべての子ノードの最上位ノード。

scope.$on('messageTwo', function( event, data ){
  scope.$broadcast( 'messageTwo', data );
});

ファイル内one.js

scope.$on('messageTwo', someValue(s));

ただし

このようにネストした子ノードすべてがこのように通信しようとすると、すぐに多数の$ on$ broadcast$ emit's.

これが私がやりたいことです。

一番上の親ノード(この場合は3...)で、これが親コントローラーになるかもしれません...

そのため、ファイル内three.js

scope.$on('pushChangesToAllNodes', function( event, message ){
  scope.$broadcast( message.name, message.data );
});

どの子ノードでも、メッセージを$ emitするか、$ onを使用してキャッチするだけです。

注:$ emitを使用せずに、1つのネストしたパスでクロストークするのは通常非常に簡単です。 $ broadcast、または$ onは、ほとんどのユースケースがノードを取得しようとしているときのものであることを意味します。1ノード2と通信する、またはその逆。

ノード2はノード1とどのように会話しますか?

ファイル内two.js

scope.$emit('pushChangesToAllNodes', sendNewChanges());

function sendNewChanges(){ // for some event.
  return { name: 'talkToOne', data: [1,2,3] };
}

ファイル内three.js - 通信に必要なすべての子ノードの最上位ノード。

私たちはすでにこれを取り扱った覚えてる?

ファイル内one.js

scope.$on('talkToOne', function( event, arrayOfNumbers ){
  arrayOfNumbers.forEach(function(number){
    console.log(number);
  });
});

キャッチしたい特定の値ごとに$ onを使用する必要がありますが、取得方法を気にせずに任意のノードで好きなものを作成できます。ジェネリックpushChangesToAllNodesをキャッチしてブロードキャストするときの、親ノードのギャップを越えたメッセージ。

お役に立てれば...

109
SoEzPz

あるコントローラから別のコントローラに$scope objectを送信するために、ここでは$rootScope.$broadcast$rootScope.$emitを最もよく使われているので議論します。

ケース1

$ rootScope。$ broadcast: -

$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name

$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event

$rootScopeリスナーは自動的には破棄されません。 $destroyを使ってそれを破壊する必要があります。 $scope.$onのリスナーは自動的に破棄されるので、$scopeを使用することをお勧めします。つまり、$ scopeが破棄されるとすぐに破棄されます。

$scope.$on('myEvent', function(event, data) {}

または、

  var customeEventListener = $rootScope.$on('myEvent', function(event, data) {

  }
  $scope.$on('$destroy', function() {
        customeEventListener();
  });

ケース2:

$ rootScope。$ emit:

   $rootScope.$emit('myEvent',$scope.data);

   $rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works

$ emitと$ broadcastの主な違いは、$ rootScope。$ emitイベントは$ rootScope。$ onを使用してリスンする必要があるという点です。これは、発行されたイベントがスコープツリーを通過しないためです。
この場合も、$ broadcastの場合と同様にリスナーを破棄する必要があります。

編集:

私は$rootScope.$broadcast + $scope.$onを使わずに$rootScope.$emit+ $rootScope.$onを使うのが好きです。 $rootScope.$broadcast + $scope.$onコンボはパフォーマンス上重大な問題を引き起こす可能性があります。これは、イベントがすべてのスコープを通じてバブルダウンするためです。

編集2

この回答で解決された問題は、angular.jsバージョン1.2.7で解決されました。 $ broadcastは未登録のスコープへのバブリングを回避し、$ emitと同じくらい速く実行されるようになりました。

38
Ved

同じアプリ内のコントローラ間でイベントを送受信するには、$ rootScopeを使用する必要があります。あなたのコントローラに$ rootScopeの依存関係を注入します。これが実用的な例です。

app.controller('firstCtrl', function($scope, $rootScope) {        
        function firstCtrl($scope) {
        {
            $rootScope.$emit('someEvent', [1,2,3]);
        }
}

app.controller('secondCtrl', function($scope, $rootScope) {
        function secondCtrl($scope)
        {
            $rootScope.$on('someEvent', function(event, data) { console.log(data); });
        }
}

$ scopeオブジェクトにリンクされたイベントは、所有者コントローラ内で動作します。コントローラ間の通信は、$ rootScopeまたはServicesを介して行われます。

10
kyasar

約束を返すサービスを自分のコントローラから呼び出して、それを自分のコントローラで使用することができます。さらに$emitまたは$broadcastを使って他のコントローラにそれを知らせます。私の場合、私は自分のサービスを通してhttp呼び出しをしなければならなかったので、私はこのようなことをしました:

function ParentController($scope, testService) {
    testService.getList()
        .then(function(data) {
            $scope.list = testService.list;
        })
        .finally(function() {
            $scope.$emit('listFetched');
        })


    function ChildController($scope, testService) {
        $scope.$on('listFetched', function(event, data) {
            // use the data accordingly
        })
    }

私のサービスはこんな感じです

    app.service('testService', ['$http', function($http) {

        this.list = [];

        this.getList = function() {
            return $http.get(someUrl)
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        list = response.data.results;

                        return response.data;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });

        }

    }])
6
ribhu
<!DOCTYPE html>
<html>

<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('MyApp',[]);
app.controller('parentCtrl',function($scope){
  $scope.$on('MyEvent',function(event,data){    
    $scope.myData = data;
  });
 });

app.controller('childCtrl',function($scope){
  $scope.fireEvent = function(){ 
  $scope.$emit('MyEvent','Any Data');
  }  
 });
</script>
</head>
<body ng-app="MyApp">
<div ng-controller="parentCtrl" ng-model="myName">

{{myData}}

 <div ng-controller="childCtrl">
   <button ng-click="fireEvent()">Fire Event</button>
 </div>

</div>
</body>
</html>
4
Prashant_M

これは私の機能です:

$rootScope.$emit('setTitle', newVal.full_name);

$rootScope.$on('setTitle', function(event, title) {
    if (scope.item) 
        scope.item.name = title;
    else 
        scope.item = {name: title};
});
4
trai bui

私はサービスとしてプロジェクトを作成するために外部のEventEmitterライブラリを追加し、必要なところにそれをインジェクトしました。だから私はスコープの継承を気にせずにどこでも "発行"と "オン"することができます。これにより問題が少なくなり、パフォーマンスが向上します。私にももっと読みやすいです。

ワイルドカードのサポート: EventEmitter2

良好なパフォーマンス: eventemitter3

その他の選択肢: ドリップ

3

スコープを使用して、イベントをスコープの子または親に伝播することができます。

$ emit - イベントを親に伝播します。 $ broadcast - イベントを子に伝播します。 $ on - $ emitと$ broadcastによって伝播されたイベントをリッスンするためのメソッド。

index.html

<div ng-app="appExample" ng-controller="EventCtrl">
      Root(Parent) scope count: {{count}}
  <div>
      <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button>
      <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button><br>

      Childrent scope count: {{count}} 
  </div>
</div>

app.js

angular.module('appExample', [])
.controller('EventCtrl', ['$scope', function($scope) {
  $scope.count = 0;
  $scope.$on('MyEvent', function() {
    $scope.count++;
  });
}]);

ここでuはコードをテストできます: http://jsfiddle.net/zp6v0rut/41/

2
Vasyl Gutnyk

以下のコードは、イベントが上位コントローラから上位コントローラにディスパッチされる2つのサブコントローラ(rootScope)を示しています。

<body ng-app="App">

    <div ng-controller="parentCtrl">

        <p>City : {{city}} </p>
        <p> Address : {{address}} </p>

        <div ng-controller="subCtrlOne">
            <input type="text" ng-model="city" />
            <button ng-click="getCity(city)">City !!!</button>
        </div>

        <div ng-controller="subCtrlTwo">

            <input type="text" ng-model="address" />
            <button ng-click="getAddrress(address)">Address !!!</button>

        </div>

    </div>

</body>
var App = angular.module('App', []);

// parent controller
App.controller('parentCtrl', parentCtrl);

parentCtrl.$inject = ["$scope"];

function parentCtrl($scope) {

    $scope.$on('cityBoom', function(events, data) {
        $scope.city = data;
    });

    $scope.$on('addrBoom', function(events, data) {
        $scope.address = data;
    });
}

// sub controller one

App.controller('subCtrlOne', subCtrlOne);

subCtrlOne.$inject = ['$scope'];

function subCtrlOne($scope) {

    $scope.getCity = function(city) {

        $scope.$emit('cityBoom', city);    
    }
}

// sub controller two

App.controller('subCtrlTwo', subCtrlTwo);

subCtrlTwo.$inject = ["$scope"];

function subCtrlTwo($scope) {

    $scope.getAddrress = function(addr) {

        $scope.$emit('addrBoom', addr);   
    }
}

http://jsfiddle.net/shushanthp/zp6v0rut/

2

Angularjsイベントの文書によると、受信側は次のような構造を持つ引数を含むべきです。

@params

- {Object}イベントはイベントに関する情報を含むイベントオブジェクトです

- 呼び出し先によって渡される{Object}引数(これは常に1つの辞書オブジェクトで送信するほうがよいので注意してください)

$scope.$on('fooEvent', function (event, args) { console.log(args) });あなたのコードから

また、異なるコントローラ間で共有できる情報を取得しようとしている場合は、それを実現するもう1つの方法があります。これは、角度付きサービスです。サービスはシングルトンです。そのサービス内の関数を設定し、これらの関数を公開し、サービス内でグローバル変数を作成し、それらを使用して情報を保存します。

0
Wajih Siddiqui

最も簡単な方法:

HTML

  <div ng-app="myApp" ng-controller="myCtrl"> 

        <button ng-click="sendData();"> Send Data </button>

    </div>

JavaScript

    <script>
        var app = angular.module('myApp', []);
        app.controller('myCtrl', function($scope, $rootScope) {
            function sendData($scope) {
                var arrayData = ['sam','rumona','cubby'];
                $rootScope.$emit('someEvent', arrayData);
            }

        });
        app.controller('yourCtrl', function($scope, $rootScope) {
            $rootScope.$on('someEvent', function(event, data) {
                console.log(data); 
            }); 
        });
    </script>
0
Sangwin Gawande