$ on e $ trasmessi in angolare


282

Ho un footerController e codeScannerController con diverse visualizzazioni.

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

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

Quando clicco su in <li>in footer.html dovrei ottenere questo evento in codeScannerController.

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

Penso che possa essere realizzato con $one $broadcast, ma non so come e non riesco a trovare esempi da nessuna parte.

Risposte:


631

Se si desidera $broadcastutilizzare $rootScope:

$scope.startScanner = function() {

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

E quindi per ricevere, usa il $scopecontroller:

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

    // do what you want to do
});

Se vuoi puoi passare degli argomenti quando $broadcast:

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

E poi riceverli:

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

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

Documentazione per questo all'interno dei documenti Scope .


2
Puoi nominare l'evento come preferisci.
Davin Tryon,

5
Assicurati di essere $ scope. $ Apply (); le tue modifiche!
Ismail,

4
@Ismail Perché ... e dove?
Jaans,

7
Esistono pratiche consigliate per l'archiviazione di queste stringhe da qualche parte piuttosto che per codificare il messaggio broadcast?
rperryng,

8
@Ismail $scope.$apply()è necessario solo quando si cambia il modello al di fuori del framework angolare (come in setTimeout, callback di dialoghi o callback ajax), in altre parole $apply()è già attivato dopo che tutto il codice .$on()è terminato.
thuuiguy,

97

In primo luogo, una breve descrizione $on(), $broadcast()e$emit() :

  • .$on(name, listener) - Ascolta un evento specifico per un dato name
  • .$broadcast(name, args)- Trasmetti un evento attraverso il $scopedi tutti i bambini
  • .$emit(name, args)- Emette un evento nella $scopegerarchia a tutti i genitori, incluso il$rootScope

Basato sul seguente HTML (vedi l'esempio completo qui ):

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

Gli eventi sparati attraverseranno il modo $scopesseguente:

  • Broadcast 1: verrà visualizzato solo dal controller 1 $scope
  • Emetti 1 - Verrà visualizzato dal controller 1 $scopequindi$rootScope
  • Broadcast 2 - Verrà visualizzato dal controller 2, $scopequindi dal controller 3$scope
  • Emetti 2 - Verrà visualizzato dal controller 2 $scopeallora$rootScope
  • Broadcast 3: verrà visualizzato solo dal controller 3 $scope
  • Emetti 3 - Verrà visualizzato dal controller 3 $scope, dal controller 2 $scopequindi$rootScope
  • Radice di trasmissione: verrà visualizzata da $rootScopee$scope tra tutti i controller (1, 2, quindi 3)
  • Emetti radice: sarà visibile solo da $rootScope

JavaScript per attivare eventi (di nuovo, puoi vedere un esempio funzionante qui ):

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

come posso immaginare la gerarchia della mia app con l'esempio che hai fornito. Come può un controller essere un genitore o un figlio? Quello che sto cercando di dire è che ho una serie di stati, ad es. LoginCtrl -> homeCrl -> notificationCtrl e così via.
HIRA THAKUR,

26

Una cosa che dovresti sapere è $ prefisso si riferisce a un metodo angolare, $$ prefissi si riferisce a metodi angolari che dovresti evitare di usare.

di seguito è riportato un modello di esempio e i suoi controller, esploreremo come $ broadcast / $ on può aiutarci a ottenere ciò che vogliamo.

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

I controller sono

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

    }
});

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

});

La mia domanda è: come si passa il nome al secondo controller quando un utente fa clic su Register? Potresti trovare più soluzioni, ma quella che useremo sta usando $ broadcast e $ on.

$ broadcast vs $ emit

Quale dovremmo usare? $ broadcast canalizzerà verso tutti gli elementi dom per i bambini e $ emit canalizzerà la direzione opposta a tutti gli elementi dom degli antenati.

Il modo migliore per evitare di decidere tra $ emit o $ broadcast è di canalizzare da $ rootScope e usare $ broadcast a tutti i suoi figli. Il che rende il nostro caso molto più semplice poiché i nostri elementi dom sono fratelli.

Aggiunge $ rootScope e consente a $ broadcast

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

Nota che abbiamo aggiunto $ rootScope e ora stiamo usando $ broadcast (broadcastName, argomenti). Per broadcastName, vogliamo assegnargli un nome univoco in modo da poterlo prendere nel nostro secondo Ctrl. Ho scelto BOOM! solo per divertimento. Il secondo argomento "argomenti" ci consente di trasmettere valori agli ascoltatori.

Ricezione della nostra trasmissione

Nel nostro secondo controller, dobbiamo impostare il codice per ascoltare la nostra trasmissione

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

È davvero così semplice. Esempio live

Altri modi per ottenere risultati simili

Cerca di evitare l'uso di questa suite di metodi in quanto non è né efficiente né facile da mantenere, ma è un modo semplice per risolvere i problemi che potresti avere.

Di solito puoi fare la stessa cosa utilizzando un servizio o semplificando i tuoi controller. Non ne discuteremo in dettaglio, ma ho pensato di menzionarlo per completezza.

Infine, tieni presente che una trasmissione davvero utile da ascoltare è di nuovo "$ destroy", puoi vedere $ significa che è un metodo o un oggetto creato dai codici fornitore. Ad ogni modo $ destroy viene trasmesso quando un controller viene distrutto, potresti voler ascoltare questo per sapere quando il controller viene rimosso.


2
Come avvertimento, prova a non utilizzare troppe trasmissioni / emissioni nella tua app. Possono essere estremamente difficili da gestire soprattutto in una grande app poiché tracciare le radici di questi eventi è un compito molto difficile.
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();
       };
    }); }());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.