$ scope。$ emitおよび$ scope。$ onの操作


887

とメソッド$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機能しますか?


6
将来の読者のためだけに:$rootScope回避できる場合は、ブロードキャスト/エミットに使用しないでください。
ミスタリス

回答:


1499

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

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

コントローラー(スコープ)の関係については何も知りませんが、いくつかのオプションがあります。

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

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

8
サービスからコントローラーにイベントを発生させる方法はありますか?
Zlatko、2014年

29
はい、理論的には$rootScope、サービスに注入して、サービスからイベントをブロードキャストできます。
zbynour 2014年

13
@Zlatkoデフォルトではサービスにスコープがなく、イベントシステムに参加するにはスコープが必要だと思います。したがって、サービスにスコープを提供する必要があります。$ rootScopeはこれに対する最も汎用的なソリューションですが、サービスが別のスコープからイベントを送信するようにしたい場合、コントローラーはサービスにプロパティを設定することによってそのスコープをサービスに渡すことができ、サービスはこれを使用できますコントローラのスコープ。より簡単な方法は、コントローラーがサービスに直接呼び出すことができる関数をサービスに提供することです。
オランデニソン2014

3
あなたはインラインフレームを使用している場合、この記事は参考になりますcharemza.name/blog/posts/angularjs/iframe/...
レティシア

1
サービスはインジェクトでき​​ますが$rootScope、サービス(から$rootScope)からイベントを発行した場合でも、イベントがパーコレーションすることを知りたいです$rootScope。なぜなら、$broadcast階層をDOWNに$emitパーコレートし、UPにパーコレートする場合-ブロードキャスター/エミッターはリスナー(?)でもあるため、「UP」と「DOWN」の間に何が起こるかです。イベントをすべての「UPWARD」およびすべての「DOWNWARD」スコープに対してサイレントにしたいが、ディスパッチャと同じレベルでのみ「聞こえる」ようにするにはどうすればよいですか?
Cody

145

さらに、@ zbynourによって提案されたオプションのより良い代替手段として、4番目のオプションを提案します。

$rootScope.$emitではなく使用$rootScope.$broadcast関係なく、コントローラをtrasmittingと受信との関係。そのように、一連の内部イベントが残る$rootScope.$$listenersとのに対し$rootScope.$broadcast、おそらく、とにかくそのイベントのリスナーではありませんほとんどが、すべての子供たちのスコープにイベントが伝播します。そしてもちろん、受信側のコントローラでは、を使用するだけ$rootScope.$onです。

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

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

3
これは基本的に中央イベントバスとして機能しますか?
jusopi 14年

5
ある意味では、イベントの伝播を回避できるというメリットがあります。
Thalis K.

3
@ThalisK。このオプションをありがとう。伝播は回避されますが、一方で$rootScopeコントローラーへの注入が必要になります(一般的には必要ありません)。しかし、確かに別のオプション、thx!
zbynour 14

77
$ rootScopeは永久に存続することに注意してください。コントローラーが2回実行されると、コントローラー内の$ rootScope。$ onが2回実行され、キャッチされたイベントによりコールバックが2回呼び出されます。代わりに$ scope。$ onを使用する場合、コールバックはコントローラーとともにAngularJSによって暗黙的に破棄されます。
Filip Sobczak 2014年

1
@FilipSobczakコメントによると、次のコードjsfiddle.net/ndqexjsg/1
Krzysztof Grzybek

111

。$ emitメソッドと。$ onメソッドを使用して、1つのコントローラーから別のコントローラーに$ scopeオブジェクトを送信するにはどうすればよいですか?

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

ブロードキャストエミットがどのように機能するかについて簡単に説明します。

以下のノードに注意してください。ノード3内にすべてネストされています。このシナリオでは、ブロードキャストエミットを使用します。

注:この例の各ノードの数は任意です。それは簡単に一番です。数2; または1,348です。各番号は、この例の単なる識別子です。この例のポイントは、Angularコントローラ/ディレクティブのネストを示すことです。

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

ファイルone.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がすぐに表示されます。

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

最上部のPARENT NODE(この場合は3)で、これは親コントローラーである可能性があります...

したがって、three.jsファイルで

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

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

注:通常、$ emit$ broadcast、または$ onを使用せずに1つのネストされたパスでクロストークすることは非常に簡単です。つまり、ほとんどのユースケースは、ノード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

お役に立てれば...


3、2、1のどれを決定するのですか?
HIRA THAKUR、2015

3、2、および1は、ネストされたコントローラーまたはディレクティブです。アプリを作成するときは、ネストを念頭に置き、上記のロジックを適用してください。例として、3はアプリケーションの$ rootScopeと言えます。すべてがその下にネストされています 3、2、1は任意です。
SoEzPz

素晴らしい例!ただし、コントローラーのグループと通信するには、親で独自のイベントディスパッチャーを使用する方がよいと私はまだ考えています。また、ディスパッチャの作成をサービスとして維持し、パターンとして使用するのにも役立ちます。
DenisKolodin 2015年

1
したがって、$ broadcastの角度付きドキュメントに よるThe event life cycle starts at the scope on which $broadcast was called. All listeners listening for name event on this scope get notified. $on('x', function(e, data) { $broadcast('x', data) })、ctrl3でctrl2と通信するctrl1を実装すると、(私のような)無限ループが発生します。放送する前にこれらの回線が必要になります。if (e.targetScope.$id === $scope.$id) { return; }
Renato Gama

39

$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と同じくらい速く実行されます。


10

同じアプリ内のコントローラー間でイベントを送信およびキャプチャするには、$ 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またはサービスを介して行われます。


7

コントローラーからサービスを呼び出してpromiseを返し、それをコントローラーで使用できます。さらに、$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);
                });

        }

    }])

4

これは私の機能です:

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

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

1
rootScopeが乱雑になるので、これは悪い習慣だと思います。stackoverflow.com/questions/24830679/…を
SKuijers

4
<!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>

2

スコープを使用して、イベントをスコープの子または親に伝播、ディスパッチできます。

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

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


2

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

<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/


0

angularjsイベントドキュメントによると、受信側には次のような構造の引数が含まれているはずです

@params

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

-呼び出し先によって渡される{Object}引数(これは、常にディクショナリオブジェクトで送信する方がよいので、1つだけであることに注意してください)

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

また、異なるコントローラ間で共有される情報を取得しようとしている場合、それを実現する別の方法があります。これは、角度のあるサービスです。サービスはシングルトンであるため、コントローラ間で情報を格納およびフェッチできます。単純にgetterを作成し、そのサービス内のセッター関数、これらの関数を公開し、サービス内にグローバル変数を作成し、それらを使用して情報を格納します


0

最も簡単な方法:

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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.