web-dev-qa-db-fra.com

$ on et $ broadcast in angular

J'ai un footerController et un codeScannerController avec différentes vues.

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

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

Lorsque je clique sur un <li> dans footer.html, je devrais obtenir cet événement dans codeScannerController.

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

Je pense que cela peut être réalisé avec $on et $broadcast, mais je ne sais pas comment et je ne peux pas trouver d’exemples nulle part.

274
Alice Polansky

Si vous voulez $broadcast utilisez le $rootScope:

$scope.startScanner = function() {

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

Et puis pour recevoir, utilisez le $scope de votre contrôleur:

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

    // do what you want to do
});

Si vous le souhaitez, vous pouvez passer des arguments lorsque vous $broadcast:

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

Et ensuite les recevoir:

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

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

Documentation à ce sujet à l'intérieur de Scope docs .

619
Davin Tryon

Tout d’abord, une brève description de $on(), $broadcast() ET $emit() :

  • .$on(name, listener) - Écoute un événement spécifique par un name donné
  • .$broadcast(name, args) - Diffuse un événement via le $scope de tous les enfants
  • .$emit(name, args) - Émet un événement vers le haut de la hiérarchie $scope à tous les parents, y compris le $rootScope

Basé sur le code HTML suivant (voir exemple complet ici ):

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

Les événements déclenchés traverseront le $scopes comme suit:

  • Broadcast 1 - Ne sera vu que par le contrôleur 1 $scope
  • Emit 1 - Sera vu par le contrôleur 1 $scope puis $rootScope
  • Broadcast 2 - Sera vu par le contrôleur 2 $scope puis par le contrôleur 3 $scope
  • Emit 2 - Sera vu par le contrôleur 2 $scope puis $rootScope
  • Broadcast 3 - Ne sera vu que par le contrôleur 3 $scope
  • Emit 3 - Sera vu par le contrôleur 3 $scope, le contrôleur 2 $scope puis $rootScope
  • Broadcast Root - Sera vu par $rootScope et $scope de tous les contrôleurs (1, 2 puis 3).
  • Emit Root - Ne sera vu que par $rootScope

JavaScript pour déclencher des événements (encore une fois, vous pouvez voir un exemple de travail ici ):

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

Une chose que vous devez savoir, c'est que $ prefix fait référence à une méthode Angular, les préfixes $$ se rapportant à angular méthodes que vous devriez éviter d'utiliser.

vous trouverez ci-dessous un exemple de modèle et ses contrôleurs. Nous verrons comment $ broadcast/$ on peut nous aider à atteindre nos objectifs.

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

Les contrôleurs sont

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

    }
});

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

});

Ma question est la suivante: comment passez-vous le nom du second contrôleur lorsqu'un utilisateur clique sur le registre? Vous pouvez proposer plusieurs solutions, mais celle que nous allons utiliser utilise $ broadcast et $ on.

$ broadcast vs $ emit

Que devrions-nous utiliser? $ broadcast transmettra tous les éléments dom enfants et $ emit canalisera la direction opposée à tous les éléments ancom dom.

Le meilleur moyen d'éviter de décider entre $ emit ou $ broadcast est de canaliser à partir de $ rootScope et d'utiliser $ broadcast pour tous ses enfants. Ce qui rend notre cas beaucoup plus facile puisque nos éléments de dom sont des frères et soeurs.

Ajout de $ rootScope et permet à $ broadcast

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

Notez que nous avons ajouté $ rootScope et que nous utilisons maintenant $ broadcast (broadcastName, arguments). Pour broadcastName, nous voulons lui attribuer un nom unique afin que nous puissions saisir ce nom dans notre secondCtrl. J'ai choisi BOOM! juste pour le fun. Le second argument, "arguments", nous permet de transmettre des valeurs aux auditeurs.

Recevoir notre émission

Dans notre deuxième contrôleur, nous devons configurer le code pour écouter notre diffusion

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

C'est vraiment aussi simple que cela. Exemple en direct

Autres moyens d'obtenir des résultats similaires

Essayez d'éviter d'utiliser cette suite de méthodes, car elle n'est ni efficace, ni facile à gérer, mais constitue un moyen simple de résoudre les problèmes que vous pourriez rencontrer.

Vous pouvez généralement faire la même chose en utilisant un service ou en simplifiant vos contrôleurs. Nous ne discuterons pas de cela en détail mais je pensais que je le mentionnerais simplement pour être complet.

Enfin, gardez à l'esprit une émission très utile à écouter: "$ destroy": vous pouvez voir que $ signifie qu'il s'agit d'une méthode ou d'un objet créé par les codes de fournisseur. Quoi qu'il en soit, $ destroy est diffusé quand un contrôleur est détruit, vous pouvez l'écouter pour savoir quand votre contrôleur est supprimé.

26
Yang Li
//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();
       };
    }); }());
1
Sandy