Bekerja dengan $ scope. $ Emit dan $ scope. $ On


887

Bagaimana saya bisa mengirim $scopeobjek saya dari satu pengontrol ke yang lain menggunakan .$emitdan .$onmetode?

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

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

Itu tidak bekerja seperti yang saya pikir seharusnya. Bagaimana $emitdan $onbekerja?


6
Hanya untuk pembaca masa depan: jangan gunakan $rootScopeuntuk siaran / siaran ketika itu bisa dihindari.
Mistalis

Jawaban:


1499

Pertama-tama, hubungan lingkup orang tua-anak memang penting. Anda memiliki dua kemungkinan untuk memancarkan beberapa peristiwa:

  • $broadcast - Mengirim acara ke bawah ke semua ruang lingkup anak,
  • $emit - Mengirim acara ke atas melalui hierarki lingkup.

Saya tidak tahu apa-apa tentang hubungan kontroler (cakupan) Anda, tetapi ada beberapa opsi:

  1. Jika ruang lingkup firstCtrladalah induk dari secondCtrlruang lingkup, kode Anda harus berfungsi dengan mengganti $emitdengan $broadcastdi firstCtrl:

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
  2. Jika tidak ada hubungan orangtua-anak di antara cakupan Anda, Anda dapat menyuntikkan $rootScopeke controller dan menyiarkan acara ke semua cakupan anak (yaitu juga secondCtrl).

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
  3. Akhirnya, ketika Anda harus mengirim acara dari pengendali anak ke cakupan yang dapat Anda gunakan $scope.$emit. Jika ruang lingkup firstCtrladalah induk dari secondCtrlruang lingkup:

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

8
Apakah ada cara untuk memecat suatu peristiwa dari layanan ke controller?
Zlatko

29
Ya secara teori Anda bisa menyuntikkan $rootScopeke layanan Anda dan menyiarkan acara dari layanan.
zbynour

13
@ Zlatko Saya cukup yakin bahwa layanan secara default tidak memiliki ruang lingkup, dan Anda memerlukan ruang lingkup untuk berpartisipasi dalam sistem acara. Jadi, entah bagaimana Anda perlu menyediakan cakupan untuk layanan Anda. $ rootScope adalah solusi tujuan umum untuk itu, tetapi jika Anda ingin layanan Anda mengirim acara dari cakupan yang berbeda, controller Anda bisa meneruskan cakupannya ke layanan dengan menetapkan properti pada layanan tersebut, dan sekarang layanan dapat menggunakan ruang lingkup pengendali. Teknik yang lebih lurus ke depan mungkin bagi pengontrol untuk menyediakan fungsi ke layanan yang dapat dipanggil langsung oleh layanan.
Oran Dennison

3
Jika Anda menggunakan iframe, artikel ini akan membantu charemza.name/blog/posts/angularjs/iframe/…
leticia

1
Layanan dapat menyuntikkan $rootScope- tetapi saya ingin tahu bahwa jika saya memancarkan suatu peristiwa dari suatu layanan (off of $rootScope), bahwa acara tersebut masih akan meresap ke $rootScope; KARENA, jika $broadcastmeresap ke hirarki, dan $emitmeresap ke atas - apa yang terjadi antara "ke atas" dan "ke bawah" - karena penyiar / emitor juga adalah pendengar (?). Bagaimana jika saya ingin acara tersebut diam untuk cakupan SEMUA "KE ATAS" dan SEMUA "KE BAWAH", tetapi hanya dapat 'terdengar' pada tingkat yang sama dengan operator?
Cody

145

Saya juga akan menyarankan opsi ke-4 sebagai alternatif yang lebih baik untuk opsi yang diusulkan oleh @zbynour.

Gunakan $rootScope.$emitdaripada $rootScope.$broadcastterlepas dari hubungan antara trasmitting dan menerima controller. Dengan begitu, acara tetap berada dalam himpunan $rootScope.$$listenerssedangkan dengan $rootScope.$broadcastacara menyebar ke semua lingkup anak-anak, sebagian besar yang mungkin tidak akan menjadi pendengar dari acara itu pula. Dan tentu saja di ujung pengontrol penerima Anda hanya menggunakan $rootScope.$on.

Untuk opsi ini Anda harus ingat untuk menghancurkan pendengar rootScope pengendali:

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

3
Ini pada dasarnya akan berfungsi sebagai bus acara pusat yang benar?
jusopi

5
Dalam arti ya, manfaatnya adalah Anda menghindari penyebaran acara.
Thalis K.

3
@ThalisK. terima kasih untuk opsi ini. Ini menghindari propagasi tetapi di sisi lain itu membutuhkan $rootScopeinjeksi ke pengontrol (apa yang tidak diperlukan secara umum). Tapi tentunya pilihan lain, thx!
zbynour

77
Berhati-hatilah karena $ rootScope hidup selamanya. Jika controller Anda dijalankan dua kali, $ rootScope. $ Di dalamnya akan dijalankan dua kali, dan peristiwa yang tertangkap akan menghasilkan panggilan balik dipanggil dua kali. Jika Anda menggunakan $ scope. $ On sebagai gantinya, callback akan dihancurkan bersama dengan controller Anda secara implisit oleh AngularJS.
Filip Sobczak

1
Menurut komentar @FilipSobczak, Anda dapat menghindari perilaku yang tidak diinginkan ini dengan melepaskan pengikat pada acara $ destroy dengan kode berikut jsfiddle.net/ndqexjsg/1
Krzysztof Grzybek

111

Bagaimana saya bisa mengirim objek $ scope saya dari satu controller ke yang lain menggunakan metode $ emit dan. $ On?

Anda dapat mengirim objek apa pun yang Anda inginkan dalam hierarki aplikasi Anda, termasuk $ scope .

Berikut adalah ide singkat tentang bagaimana siaran dan memancarkan kerja.

Perhatikan simpul-simpul di bawah ini; semua bersarang dalam simpul 3. Anda menggunakan siaran dan memancarkan ketika Anda memiliki skenario ini.

Catatan: Jumlah setiap node dalam contoh ini adalah arbitrer; bisa dengan mudah menjadi yang pertama; nomor dua; atau bahkan nomor 1.348. Setiap angka hanyalah pengidentifikasi untuk contoh ini. Maksud dari contoh ini adalah untuk menunjukkan bersarangnya pengontrol / arahan sudut.

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

Lihatlah pohon ini. Bagaimana Anda menjawab pertanyaan-pertanyaan berikut?

Catatan: Ada cara lain untuk menjawab pertanyaan-pertanyaan ini, tetapi di sini kita akan membahas siaran dan emisi . Juga, ketika membaca teks di bawah ini anggap setiap angka memiliki file sendiri (direktif, controller) ex one.js, two.js, three.js.

Bagaimana simpul 1 berbicara dengan simpul 3 ?

Dalam file one.js

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

Dalam file three.js - simpul paling atas untuk semua simpul anak yang diperlukan untuk berkomunikasi.

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

Bagaimana simpul 2 berbicara dengan simpul 3?

Dalam file two.js

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

Dalam file three.js - simpul paling atas untuk semua simpul anak yang diperlukan untuk berkomunikasi.

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

Bagaimana simpul 3 berbicara dengan simpul 1 dan / atau simpul 2?

Dalam file three.js - simpul paling atas untuk semua simpul anak yang diperlukan untuk berkomunikasi.

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

Dalam file one.js && two.js file mana saja yang ingin Anda tangkap pesannya atau keduanya.

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

Bagaimana simpul 2 berbicara dengan simpul 1?

Dalam file two.js

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

Dalam file three.js - simpul paling atas untuk semua simpul anak yang diperlukan untuk berkomunikasi.

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

Dalam file one.js

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

NAMUN

Ketika Anda memiliki semua simpul anak bersarang yang mencoba berkomunikasi seperti ini, Anda akan dengan cepat melihat banyak $ on , $ broadcast , dan $ emit .

Inilah yang ingin saya lakukan.

Di PARENT NODE paling atas ( 3 dalam hal ini ...), yang mungkin merupakan pengendali orang tua Anda ...

Jadi, dalam file three.js

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

Sekarang di salah satu node anak Anda hanya perlu $ memancarkan pesan atau menangkapnya menggunakan $ on .

CATATAN: Biasanya cukup mudah untuk melakukan percakapan silang dalam satu jalur bertingkat tanpa menggunakan $ emit , $ broadcast , atau $ on , yang berarti sebagian besar kasus penggunaan adalah ketika Anda mencoba untuk mendapatkan simpul 1 untuk berkomunikasi dengan simpul 2 atau sebaliknya.

Bagaimana simpul 2 berbicara dengan simpul 1?

Dalam file two.js

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

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

Dalam file three.js - simpul paling atas untuk semua simpul anak yang diperlukan untuk berkomunikasi.

Kami sudah menangani yang ini ingat?

Dalam file one.js

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

Anda masih perlu menggunakan $ pada dengan setiap nilai spesifik yang ingin Anda tangkap, tetapi sekarang Anda dapat membuat apa pun yang Anda suka di salah satu node tanpa harus khawatir tentang bagaimana untuk mendapatkan pesan melintasi celah simpul orangtua saat kami menangkap dan menyiarkan pushChangesToAllNodes generik .

Semoga ini membantu...


bagaimana cara memutuskan mana yang 3,2 dan 1?
HIRA THAKUR

3, 2, dan 1 adalah kontroler atau arahan bersarang. Saat Anda membuat aplikasi, ingatlah sarang Anda dan terapkan logika di atas. Sebagai contoh, kita dapat mengatakan 3 adalah $ rootScope dari aplikasi; dan semuanya bersarang di bawahnya. 3, 2, dan 1 adalah arbitrer.
SoEzPz

Contoh yang bagus! Tapi aku masih berpikir bahwa lebih baik menggunakan sendiri event-operator di orang tua untuk berkomunikasi kelompok pengontrol. Juga berguna untuk menjaga kreasi operator sebagai layanan untuk menggunakannya sebagai pola.
DenisKolodin

1
Menurut dokumen sudut pada $ 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. maka Anda (seperti saya) akan mendapatkan loop tak terbatas jika Anda menerapkan ctrl1 berbicara ke ctrl2 dengan $on('x', function(e, data) { $broadcast('x', data) })pada ctrl3. Anda perlu saluran ini sebelum siaran; if (e.targetScope.$id === $scope.$id) { return; }
Renato Gama

39

Untuk mengirim $scope objectdari satu pengontrol ke pengontrol lainnya, saya akan membahas tentang $rootScope.$broadcastdan di $rootScope.$emitsini karena mereka paling banyak digunakan.

Kasus 1 :

$ rootScope. $ broadcast: -

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

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

$rootScopependengar tidak dimusnahkan secara otomatis. Anda perlu menghancurkannya menggunakan $destroy. Lebih baik digunakan $scope.$onkarena pendengar $scopedihancurkan secara otomatis yaitu segera setelah $ scope dihancurkan.

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

Atau,

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

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

Kasus 2:

$ rootScope. $ emit:

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

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

Perbedaan utama dalam $ emit dan $ broadcast adalah $ rootScope. $ Emit event harus didengarkan menggunakan $ rootScope. $ On, karena peristiwa yang dipancarkan tidak pernah turun melalui pohon lingkup. .
Dalam hal ini Anda juga harus menghancurkan pendengar seperti dalam kasus $ broadcast.

Edit:

Saya lebih suka tidak menggunakan $rootScope.$broadcast + $scope.$ontetapi menggunakan $rootScope.$emit+ $rootScope.$on. The $rootScope.$broadcast + $scope.$oncombo dapat menyebabkan masalah kinerja yang serius. Itu karena acara tersebut akan menyebar melalui semua lingkup.

Edit 2 :

Masalah yang dibahas dalam jawaban ini telah diatasi dalam angular.js versi 1.2.7. $ broadcast sekarang menghindari penggeledahan atas cakupan yang tidak terdaftar dan berjalan secepat $ emit.


10

Anda harus menggunakan $ rootScope untuk mengirim dan menangkap peristiwa antara pengontrol di aplikasi yang sama. Suntikkan dependensi $ rootScope ke pengontrol Anda. Berikut ini contoh kerjanya.

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

Acara yang ditautkan ke objek $ scope hanya berfungsi di pengontrol pemilik. Komunikasi antara pengontrol dilakukan melalui $ rootScope atau Layanan.


7

Anda dapat memanggil layanan dari controller Anda yang mengembalikan janji dan kemudian menggunakannya di controller Anda. Dan selanjutnya gunakan $emitatau $broadcastuntuk memberi tahu pengontrol lain tentang hal itu. Dalam kasus saya, saya harus melakukan panggilan http melalui layanan saya, jadi saya melakukan sesuatu seperti ini:

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

dan layanan saya terlihat seperti ini

    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

Ini adalah fungsi saya:

$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
Saya pikir ini adalah praktik yang buruk karena rootScope Anda akan berantakan. Lihat 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

Lingkup dapat digunakan untuk menyebarkan, mengirimkan acara ke lingkup anak-anak atau orang tua.

$ emit - menyebarkan acara ke induk. $ broadcast - menyebarkan acara ke anak-anak. $ on - metode untuk mendengarkan acara, disebarkan oleh $ emit dan $ broadcast.

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

contoh app.js :

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

Di sini Anda dapat menguji kode: http://jsfiddle.net/zp6v0rut/41/


2

Kode di bawah ini menunjukkan dua sub-pengendali dari tempat kejadian dikirim ke atas ke pengendali induk (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/


0

Menurut acara angularjs, pihak penerima harus berisi argumen dengan struktur seperti

@params

- {Object} acara menjadi objek acara yang berisi info tentang acara tersebut

- {Object} args yang dilewatkan oleh callee (Perhatikan bahwa ini hanya bisa jadi yang lebih baik untuk selalu mengirim objek kamus)

$scope.$on('fooEvent', function (event, args) { console.log(args) }); Dari kode Anda

Juga jika Anda mencoba untuk mendapatkan informasi yang dibagikan agar tersedia di berbagai pengontrol yang berbeda, ada cara lain untuk mencapai itu dan itu adalah layanan bersudut. Karena layanan tersebut layanan informasi lajang dapat disimpan dan diambil di seluruh pengontrol. fungsi setter dalam layanan itu, memaparkan fungsi-fungsi ini, membuat variabel global dalam layanan dan menggunakannya untuk menyimpan info


0

Cara termudah:

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>
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.