$ aktif dan $ siaran dalam sudut

282

Saya memiliki footerController dan codeScannerController dengan tampilan berbeda.

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

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

Ketika saya mengklik <li>di footer.html saya harus mendapatkan acara ini di codeScannerController.

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

Saya pikir itu bisa diwujudkan dengan $ondan $broadcast, tetapi saya tidak tahu bagaimana dan tidak dapat menemukan contoh di mana pun.

Alice Polansky
sumber

Jawaban:

631

Jika Anda ingin $broadcastmenggunakan $rootScope:

$scope.startScanner = function() {

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

Dan kemudian untuk menerima, gunakan $scopecontroller Anda:

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

    // do what you want to do
});

Jika mau, Anda bisa memberikan argumen saat $broadcast:

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

Dan kemudian menerimanya:

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

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

Dokumentasi untuk ini di dalam ruang lingkup dokumen .

Davin Tryon
sumber
2
Anda dapat memberi nama acara apa pun yang Anda suka.
Davin Tryon
5
Pastikan Anda $ scope. $ Apply (); perubahan Anda!
Ismail
4
@ Ismail Kenapa ... dan di mana?
Jaans
7
Apakah ada praktik yang disarankan untuk menyimpan string ini di suatu tempat daripada hardcoding pesan siaran?
rperryng
8
@Ismail $scope.$apply()hanya diperlukan ketika mengubah model di luar kerangka sudut (seperti di setTimeout, panggilan balik dialog, atau panggilan balik ajax), dengan kata lain$apply() sudah dipicu setelah semua kode di .$on()selesai.
th3uiguy
97

Pertama, deskripsi singkat tentang $on(), $broadcast()dan$emit() :

  • .$on(name, listener) - Mendengarkan acara tertentu dengan diberikan name
  • .$broadcast(name, args)- Siarkan acara melalui $scopesemua anak
  • .$emit(name, args)- Mengeluarkan acara hingga $scopehirarki untuk semua orang tua, termasuk$rootScope

Berdasarkan HTML berikut (lihat contoh lengkap di sini ):

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

Acara yang dipecat akan melintasi $scopessebagai berikut:

  • Siaran 1 - Hanya akan dilihat oleh Pengendali 1 $scope
  • Emit 1 - Akan terlihat oleh Controller 1 $scopelalu$rootScope
  • Siaran 2 - Akan terlihat oleh Kontroler 2 $scopelalu Kontroler 3$scope
  • Emit 2 - Akan terlihat oleh Controller 2 $scopelalu$rootScope
  • Siaran 3 - Hanya akan dilihat oleh Pengendali 3 $scope
  • Emit 3 - Akan terlihat oleh Controller 3 $scope, Controller 2 $scopelalu$rootScope
  • Root Siaran - Akan dilihat oleh $rootScopedan $scopesemua Pengendali (1, 2 lalu 3)
  • Emit Root - Hanya akan dilihat oleh $rootScope

JavaScript untuk memicu peristiwa (sekali lagi, Anda dapat melihat contoh yang berfungsi di sini ):

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');
    });
}]);
th3uiguy
sumber
bagaimana saya bisa membayangkan hierarki aplikasi saya dengan contoh yang Anda berikan. Bagaimana pengontrol bisa menjadi orang tua atau anak. ?? Apa yang ingin saya katakan adalah bahwa saya memiliki serangkaian keadaan misalnya. LoginCtrl -> homeCrl -> notificationCtrl dan sebagainya.
HIRA THAKUR
26

Satu hal yang harus Anda ketahui adalah $ awalan merujuk ke Metode Angular, $$ awalan mengacu pada metode sudut yang harus Anda hindari menggunakan.

di bawah ini adalah contoh template dan pengontrolnya, kita akan mengeksplorasi bagaimana $ broadcast / $ on dapat membantu kita mencapai apa yang kita inginkan.

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

Kontrolernya adalah

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

    }
});

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

});

Pertanyaan saya kepada Anda adalah bagaimana Anda memberikan nama ke pengontrol kedua ketika pengguna mengklik daftar? Anda mungkin menemukan beberapa solusi tetapi yang akan kita gunakan adalah menggunakan $ broadcast dan $ on.

$ broadcast vs $ emit

Yang mana yang harus kita gunakan? $ broadcast akan disalurkan ke semua elemen dom anak-anak dan $ emit akan menyalurkan arah yang berlawanan ke semua elemen dom leluhur.

Cara terbaik untuk menghindari memutuskan antara $ emit atau $ broadcast adalah menyalurkan dari $ rootScope dan menggunakan $ broadcast untuk semua anak-anaknya. Yang membuat kasus kami jauh lebih mudah karena elemen dom kami adalah saudara kandung.

Menambahkan $ rootScope dan memungkinkan $ broadcast

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

Perhatikan kami menambahkan $ rootScope dan sekarang kami menggunakan $ broadcast (broadcastName, argumen). Untuk broadcastName, kami ingin memberinya nama yang unik sehingga kami dapat menangkap nama itu di Ctrl kedua kami. Saya telah memilih BOOM! hanya untuk bersenang-senang. Argumen kedua 'argumen' memungkinkan kita memberikan nilai kepada pendengar.

Menerima siaran kami

Di pengontrol kedua kami, kami perlu mengatur kode untuk mendengarkan siaran kami

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

Sangat sederhana. Contoh Langsung

Cara lain untuk mencapai hasil yang serupa

Cobalah untuk menghindari menggunakan rangkaian metode ini karena tidak efisien dan tidak mudah untuk dipelihara tetapi ini adalah cara sederhana untuk memperbaiki masalah yang mungkin Anda miliki.

Anda biasanya dapat melakukan hal yang sama dengan menggunakan layanan atau dengan menyederhanakan controller Anda. Kami tidak akan membahas ini secara rinci, tetapi saya pikir saya hanya akan menyebutkannya untuk kelengkapan.

Terakhir, perlu diingat siaran yang sangat berguna untuk didengarkan adalah '$ destroy' lagi Anda dapat melihat $ berarti itu adalah metode atau objek yang dibuat oleh kode vendor. Anyways $ destroy disiarkan ketika controller hancur, Anda mungkin ingin mendengarkan ini untuk mengetahui kapan controller Anda dihapus.

Yang Li
sumber
2
Sebagai peringatan, cobalah untuk tidak menggunakan terlalu banyak siaran / emisi di aplikasi Anda. Mereka bisa sangat sulit untuk dikelola terutama dalam aplikasi besar karena menelusuri akar dari peristiwa ini adalah tugas yang sangat sulit.
Yang Li
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();
       };
    }); }());
Sandy
sumber