Trabajando con $scope.$emit y $scope.$on
¿ Cómo puedo enviar mi $scope
objeto de un controlador a otro usando métodos .$emit
y ?.$on
function firstCtrl($scope) {
$scope.$emit('someEvent', [1,2,3]);
}
function secondCtrl($scope) {
$scope.$on('someEvent', function(mass) { console.log(mass); });
}
No funciona como creo que debería. ¿Cómo funcionan $emit
y $on
funcionan?
En primer lugar, la relación entre el ámbito padre-hijo sí importa. Tienes dos posibilidades para emitir algún evento:
$broadcast
-- envía el evento hacia abajo a todos los ámbitos secundarios,$emit
-- envía el evento hacia arriba a través de la jerarquía de alcance.
No sé nada sobre la relación de sus controladores (ámbitos), pero hay varias opciones:
Si el alcance de
firstCtrl
es padre delsecondCtrl
alcance, su código debería funcionar reemplazando$emit
por$broadcast
enfirstCtrl
:function firstCtrl($scope) { $scope.$broadcast('someEvent', [1,2,3]); } function secondCtrl($scope) { $scope.$on('someEvent', function(event, mass) { console.log(mass); }); }
En caso de que no exista una relación padre-hijo entre sus ámbitos, puede inyectar
$rootScope
en el controlador y transmitir el evento a todos los ámbitos secundarios (es decir, tambiénsecondCtrl
).function firstCtrl($rootScope) { $rootScope.$broadcast('someEvent', [1,2,3]); }
Finalmente, cuando necesite enviar el evento desde el controlador secundario a ámbitos superiores, puede usar
$scope.$emit
. Si el alcance defirstCtrl
es padre delsecondCtrl
alcance:function firstCtrl($scope) { $scope.$on('someEvent', function(event, data) { console.log(data); }); } function secondCtrl($scope) { $scope.$emit('someEvent', [1,2,3]); }
Además, sugeriría una cuarta opción como una mejor alternativa a las opciones propuestas por @zbynour.
Utilice $rootScope.$emit
en lugar de $rootScope.$broadcast
independientemente de la relación entre el controlador transmisor y receptor. De esa manera, el evento permanece dentro del conjunto $rootScope.$$listeners
mientras que $rootScope.$broadcast
el evento se propaga a todos los ámbitos secundarios, la mayoría de los cuales probablemente no serán oyentes de ese evento de todos modos. Y, por supuesto, al final del controlador receptor solo usa $rootScope.$on
.
Para esta opción debes recordar destruir los oyentes rootScope del controlador:
var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
unbindEventHandler();
});
¿Cómo puedo enviar mi objeto $scope de un controlador a otro usando los métodos .$emit y .$on?
Puedes enviar cualquier objeto que desees dentro de la jerarquía de tu aplicación, incluido $scope .
A continuación se ofrece una idea rápida sobre cómo funcionan la transmisión y la emisión .
Observe los nodos a continuación; todo anidado dentro del nodo 3. Usas transmisión y emisión cuando tienes este escenario.
Nota: El número de cada nodo en este ejemplo es arbitrario; fácilmente podría ser el número uno; el número dos; o incluso el número 1.348. Cada número es solo un identificador para este ejemplo. El objetivo de este ejemplo es mostrar el anidamiento de controladores/directivas Angular.
3
------------
| |
----- ------
1 | 2 |
--- --- --- ---
| | | | | | | |
Mira este árbol. ¿Cómo respondes a las siguientes preguntas?
Nota: Hay otras formas de responder estas preguntas, pero aquí analizaremos la transmisión y la emisión . Además, al leer el texto a continuación, asuma que cada número tiene su propio archivo (directiva, controlador), por ejemplo, one.js, two.js, three.js.
¿ Cómo le habla el nodo 1 al nodo 3 ?
En el archivo uno.js
scope.$emit('messageOne', someValue(s));
En el archivo three.js , el nodo superior para todos los nodos secundarios necesarios para comunicarse.
scope.$on('messageOne', someValue(s));
¿Cómo le habla el nodo 2 al nodo 3?
En el archivo dos.js
scope.$emit('messageTwo', someValue(s));
En el archivo three.js , el nodo superior para todos los nodos secundarios necesarios para comunicarse.
scope.$on('messageTwo', someValue(s));
¿Cómo se comunica el nodo 3 con el nodo 1 y/o el nodo 2?
En el archivo three.js , el nodo superior para todos los nodos secundarios necesarios para comunicarse.
scope.$broadcast('messageThree', someValue(s));
En el archivo one.js && two.js , cualquier archivo en el que desee capturar el mensaje o ambos.
scope.$on('messageThree', someValue(s));
¿Cómo le habla el nodo 2 al nodo 1?
En el archivo dos.js
scope.$emit('messageTwo', someValue(s));
En el archivo three.js , el nodo superior para todos los nodos secundarios necesarios para comunicarse.
scope.$on('messageTwo', function( event, data ){
scope.$broadcast( 'messageTwo', data );
});
En el archivo uno.js
scope.$on('messageTwo', someValue(s));
SIN EMBARGO
Cuando tenga todos estos nodos secundarios anidados intentando comunicarse de esta manera, verá rápidamente muchos $on , $broadcast y $emit .
Esto es lo que me gusta hacer.
En el NODO PADRE superior ( 3 en este caso...), que puede ser su controlador principal...
Entonces, en el archivo tres.js
scope.$on('pushChangesToAllNodes', function( event, message ){
scope.$broadcast( message.name, message.data );
});
Ahora en cualquiera de los nodos secundarios solo necesita $emitir el mensaje o capturarlo usando $on .
NOTA: Normalmente es bastante fácil realizar conversaciones cruzadas en una ruta anidada sin usar $emit , $broadcast o $on , lo que significa que la mayoría de los casos de uso son para cuando intenta que el nodo 1 se comunique con el nodo 2 o viceversa.
¿Cómo le habla el nodo 2 al nodo 1?
En el archivo dos.js
scope.$emit('pushChangesToAllNodes', sendNewChanges());
function sendNewChanges(){ // for some event.
return { name: 'talkToOne', data: [1,2,3] };
}
En el archivo three.js , el nodo superior para todos los nodos secundarios necesarios para comunicarse.
Este ya lo manejamos ¿recuerdas?
En el archivo uno.js
scope.$on('talkToOne', function( event, arrayOfNumbers ){
arrayOfNumbers.forEach(function(number){
console.log(number);
});
});
Aún necesitarás usar $on con cada valor específico que quieras capturar, pero ahora puedes crear lo que quieras en cualquiera de los nodos sin tener que preocuparte por cómo hacer llegar el mensaje a través del espacio del nodo principal a medida que capturamos y transmitimos. el pushChangesToAllNodes genérico .
Para enviar $scope object
de un controlador a otro, hablaré sobre $rootScope.$broadcast
y $rootScope.$emit
aquí, ya que se utilizan con mayor frecuencia.
Caso 1 :
$rootScope.$transmisión:-
$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name
$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event
$rootScope
oyente no se destruyen automáticamente. Necesitas destruirlo usando $destroy
. Es mejor usarlo $scope.$on
ya que los oyentes $scope
se destruyen automáticamente, es decir, tan pronto como se destruye $scope.
$scope.$on('myEvent', function(event, data) {}
O,
var customeEventListener = $rootScope.$on('myEvent', function(event, data) {
}
$scope.$on('$destroy', function() {
customeEventListener();
});
Caso 2:
$rootScope.$emitir:
$rootScope.$emit('myEvent',$scope.data);
$rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works
La principal diferencia entre $emit y $broadcast es que el evento $rootScope.$emit debe escucharse usando $rootScope.$on, porque el evento emitido nunca baja a través del árbol de alcance. .
En este caso también debes destruir al oyente como en el caso de $broadcast.
Editar:
Prefiero no usar
$rootScope.$broadcast + $scope.$on
pero usar$rootScope.$emit+ $rootScope.$on
. El$rootScope.$broadcast + $scope.$on
combo puede causar serios problemas de rendimiento. Esto se debe a que el evento se extenderá por todos los ámbitos.
Edición 2 :
El problema abordado en esta respuesta se resolvió en angular.js versión 1.2.7. $broadcast ahora evita la difusión en ámbitos no registrados y se ejecuta tan rápido como $emit.