web-dev-qa-db-fra.com

Travailler avec $ scope. $ Emit et $ scope. $ On

Comment puis-je envoyer mon objet $scope d'un contrôleur à un autre à l'aide des méthodes .$emit et .$on?

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

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

Cela ne fonctionne pas comme je le pense. Comment fonctionnent $emit et $on?

871
Paul Kononenko

Tout d'abord, la relation de portée parent-enfant est importante. Vous avez deux possibilités pour émettre un événement:

  • $broadcast - envoie l'événement vers le bas à toutes les portées enfant,
  • $emit - envoie l'événement par le haut dans la hiérarchie de la portée.

Je ne sais rien de votre relation contrôleurs (scopes), mais il y a plusieurs options:

  1. Si la portée de firstCtrl est parent de la portée de secondCtrl, votre code devrait fonctionner en remplaçant $emit par $broadcast dans firstCtrl:

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
    
  2. Au cas où il n'y aurait pas de relation parent-enfant entre vos portées, vous pouvez injecter $rootScope dans le contrôleur et diffuser l'événement à tous les portées enfants (c'est-à-dire aussi secondCtrl).

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  3. Enfin, lorsque vous avez besoin d'envoyer l'événement du contrôleur enfant vers le haut, vous pouvez utiliser $scope.$emit. Si la portée de firstCtrl est le parent de la portée secondCtrl:

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

Je suggérerais en outre une quatrième option comme meilleure alternative aux options proposées par @zbynour.

Utilisez $rootScope.$emit plutôt que $rootScope.$broadcast quelle que soit la relation entre le contrôleur de transfert et de réception. De cette façon, l'événement reste dans l'ensemble de $rootScope.$$listeners alors que avec $rootScope.$broadcast l'événement se propage à tous les portées des enfants, dont la plupart ne seront probablement pas à l'écoute de toute façon. Et bien sûr, du côté du contrôleur récepteur, vous utilisez simplement $rootScope.$on.

Pour cette option, vous devez vous rappeler de détruire les écouteurs rootScope du contrôleur:

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

Comment puis-je envoyer mon objet $ scope d'un contrôleur à un autre avec les méthodes. $ Emit et. $ On?

Vous pouvez envoyer n’importe quel objet de votre choix dans la hiérarchie de votre application, y compris $ scope.

Voici une rapide idée sur le fonctionnement de broadcast et emit.

Notez les nœuds ci-dessous; tous sont imbriqués dans le noeud 3. Vous utilisez diffusion et émission lorsque vous avez ce scénario.

Remarque: Le numéro de chaque nœud dans cet exemple est arbitraire; ça pourrait facilement être le numéro un; le numéro deux; ou même le nombre 1.348. Chaque numéro est juste un identifiant pour cet exemple. Le but de cet exemple est de montrer l'imbrication de contrôleurs/directives Angular.

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

Découvrez cet arbre. Comment répondez-vous aux questions suivantes?

Remarque: Il existe d'autres moyens de répondre à ces questions, mais ici, nous discuterons de diffusion et émission. En outre, lors de la lecture du texte ci-dessous, supposons que chaque numéro a son propre fichier (directive, contrôleur) e.x. un.js, deux.js, trois.js.

Comment le noeud 1 parle-t-il au noeud ?

Dans le fichier one.js

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

Dans le fichier three.js - le nœud le plus haut pour tous les nœuds enfants nécessaires à la communication.

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

Comment le noeud 2 parle-t-il au noeud 3?

Dans le fichier two.js

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

Dans le fichier three.js - le nœud le plus haut pour tous les nœuds enfants nécessaires à la communication.

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

Comment le noeud 3 parle-t-il au noeud 1 et/ou au noeud 2?

Dans le fichier three.js - le nœud le plus haut pour tous les nœuds enfants nécessaires à la communication.

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

Dans le fichier one.js && two.js le fichier dans lequel vous voulez intercepter le message ou les deux.

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

Comment le noeud 2 parle-t-il au noeud 1?

Dans le fichier two.js

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

Dans le fichier three.js - le nœud le plus haut pour tous les nœuds enfants nécessaires à la communication.

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

Dans le fichier one.js

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

CEPENDANT

Lorsque vous avez tous ces nœuds enfants imbriqués qui tentent de communiquer de cette façon, vous verrez rapidement plusieurs $ on's, $ broadcast's et $ emit's.

Voici ce que j'aime faire.

Dans le nœud parent le plus élevé ( dans ce cas ...), qui peut être votre contrôleur parent ...

Donc, dans le fichier three.js

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

Maintenant, dans n'importe lequel des nœuds enfants, il vous suffit de $ emit le message ou de l'attraper à l'aide de $ on.

NOTE: Il est normalement assez facile de passer d’un dialogue à l’autre dans un chemin imbriqué sans utiliser $ emit, $ broadcast ou $ on, ce qui signifie que la plupart des cas d’utilisation sont destinés à la communication du noeud 1 avec le noeud 2 ou vice-versa.

Comment le noeud 2 parle-t-il au noeud 1?

Dans le fichier two.js

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

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

Dans le fichier three.js - le nœud le plus haut pour tous les nœuds enfants nécessaires à la communication.

Nous avons déjà traité celui-là

Dans le fichier one.js

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

Vous aurez toujours besoin d'utiliser $ on avec chaque valeur spécifique que vous voulez intercepter, mais vous pouvez maintenant créer ce que vous voulez dans n'importe quel nœud sans avoir à vous soucier de la façon de transmettre le message au parent. intervalle de nœud lorsque nous attrapons et diffusons le générique pushChangesToAllNodes.

J'espère que cela t'aides...

109
SoEzPz

Pour envoyer $scope object d'un contrôleur à un autre, je discuterai de $rootScope.$broadcast et de $rootScope.$emit ici car ils sont le plus utilisés.

Cas 1:

$ rootScope. $ broadcast: -

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

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

$rootScope auditeur ne sont pas détruits automatiquement. Vous devez le détruire en utilisant $destroy. Il est préférable d’utiliser $scope.$on car les écouteurs de $scope sont automatiquement détruits, c'est-à-dire dès que $ scope est détruit.

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

Ou,

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

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

Cas 2:

$ rootScope. $ emit:

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

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

La différence majeure entre $ emit et $ broadcast est que les événements $ rootScope. $ Emit doivent être écoutés à l'aide de $ rootScope. $ On, car l'événement émis ne descend jamais dans l'arborescence des portées..
Dans ce cas aussi, vous devez détruire l'auditeur comme dans le cas de $ broadcast.

Edit:

Je préfère ne pas utiliser $rootScope.$broadcast + $scope.$on mais utiliser $rootScope.$emit+ $rootScope.$on. Le combo $rootScope.$broadcast + $scope.$on peut entraîner de graves problèmes de performances. C'est parce que l'événement va se propager à travers tous les domaines.

Edit 2:

Le problème traité dans cette réponse a été résolu dans la version 1.2.7 d'angular.js. $ broadcast évite maintenant les bulles sur les portées non enregistrées et s’exécute aussi rapidement que $ emit.

38
Ved

Vous devez utiliser $ rootScope pour envoyer et capturer des événements entre des contrôleurs de la même application. Injectez la dépendance $ rootScope à vos contrôleurs. Voici un exemple de travail.

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

Les événements liés à l'objet $ scope fonctionnent simplement dans le contrôleur de propriétaire. La communication entre les contrôleurs se fait via $ rootScope ou Services.

10
kyasar

Vous pouvez appeler un service de votre contrôleur qui renvoie une promesse, puis l’utiliser dans votre contrôleur. Et utilisez ensuite $emit ou $broadcast pour informer les autres contrôleurs à ce sujet. Dans mon cas, je devais passer des appels http via mon service, alors j'ai fait quelque chose comme ceci:

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

et mon service ressemble à ceci

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

        }

    }])
6
ribhu
<!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>
4
Prashant_M

Ceci est ma fonction:

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

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

J'ai fini par ajouter une bibliothèque externe EventEmitter à projeter en tant que service et à l'injecter partout où j'avais besoin. Je peux donc "émettre" et "allumer" n'importe quoi n'importe où, sans me soucier de l'héritage. C'est moins de problèmes de cette façon et certainement une meilleure performance. Aussi plus lisible pour moi.

Prise en charge des caractères génériques: EventEmitter2

Bonne performance: eventemitter

Autre alternative: goutte à goutte

3
Mustafa Dokumacı

Les étendues peuvent être utilisées pour propager, envoyer un événement aux enfants ou au parent de la portée.

$ emit - propage l'événement au parent. $ broadcast - propage l'événement aux enfants. $ on - méthode d'écoute des événements, propagée par $ emit et $ broadcast.

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

exemple app.js :

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

Ici, vous pouvez tester le code: http://jsfiddle.net/zp6v0rut/41/

2
Vasyl Gutnyk

Le code ci-dessous montre les deux sous-contrôleurs à partir desquels les événements sont envoyés vers le contrôleur parent (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/

2

Selon l’événement angularjs docs, le destinataire devrait contenir des arguments avec une structure telle que

@param

- {objet} événement étant l'objet événement contenant des informations sur l'événement

- {Object} arguments qui sont passés par l'appelé (notez qu'il ne peut s'agir que d'un exemple, il est donc préférable d'envoyer toujours un objet dictionnaire).

$scope.$on('fooEvent', function (event, args) { console.log(args) }); À partir de votre code

De même, si vous essayez de mettre à disposition un élément d’information partagé entre différents contrôleurs, il existe un autre moyen d’y parvenir: les services angular. Depuis que les services sont des singletons, les informations peuvent être stockées controllers.Simply créer des fonctions getter et setter dans ce service, exposer ces fonctions, créer des variables globales dans le service et les utiliser pour stocker les informations

0
Wajih Siddiqui

Le moyen le plus simple:

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>
0
Sangwin Gawande