javascript - $ on y $ broadcast en angular
.$broadcast angular (4)
Tengo un footerController y codeScannerController con diferentes vistas.
angular.module(''myApp'').controller(''footerController'', ["$scope", function($scope) {}]);
angular.module(''myApp'').controller(''codeScannerController'', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...
Cuando hago clic en un <li>
en footer.html debería obtener este evento en codeScannerController.
<li class="button" ng-click="startScanner()">3</li>
Creo que se puede realizar con $on
y $broadcast
, pero no sé cómo y no puedo encontrar ejemplos en ninguna parte.
Primero, una breve descripción de $on()
, $broadcast()
y $emit()
:
-
.$on(name, listener)
- Escucha un evento específico por unname
dado -
.$broadcast(name, args)
: transmite un evento a través del$scope
de todos los niños -
.$emit(name, args)
: emite un evento de la jerarquía de$scope
a todos los padres, incluido$rootScope
Basado en el siguiente HTML (ver ejemplo completo aquí ):
<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>
Los eventos disparados atravesarán los $scopes
como sigue:
- Transmisión 1: solo la verá Controller 1
$scope
- Emitir 1: será visto por Controller 1
$scope
luego$rootScope
- Difusión 2 - Serán vistos por Controller 2
$scope
luego Controller 3$scope
- Emitir 2: será visto por Controller 2
$scope
luego$rootScope
- Transmisión 3 - Solo será vista por Controller 3
$scope
- Emit 3 - Serán vistos por Controller 3
$scope
, Controller 2$scope
luego$rootScope
- Raíz de difusión: será vista por
$rootScope
y$scope
de todos los controladores (1, 2 y 3) - Emit Root - Solo será visto por
$rootScope
JavaScript para desencadenar eventos (de nuevo, puedes ver un ejemplo funcional aquí ):
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'');
});
}]);
Si quieres $broadcast
usa el $rootScope
:
$scope.startScanner = function() {
$rootScope.$broadcast(''scanner-started'');
}
Y luego para recibir, usa el $scope
de tu controlador:
$scope.$on(''scanner-started'', function(event, args) {
// do what you want to do
});
Si lo desea, puede pasar argumentos cuando $broadcast
:
$rootScope.$broadcast(''scanner-started'', { any: {} });
Y luego recibirlos:
$scope.$on(''scanner-started'', function(event, args) {
var anyThing = args.any;
// do what you want to do
});
Documentación para esto dentro de los documentos de Scope .
Una cosa que debe saber es que $ prefijo se refiere a un método angular, $$ prefijos se refiere a métodos angulares que debe evitar usar.
A continuación se muestra una plantilla de ejemplo y sus controladores. Exploraremos cómo $ broadcast / $ on puede ayudarnos a lograr lo que queremos.
<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>
Los controladores son
app.controller(''FirstCtrl'', function($scope){
$scope.register = function(){
}
});
app.controller(''SecondCtrl'', function($scope){
});
Mi pregunta para usted es ¿cómo pasa el nombre al segundo controlador cuando un usuario hace clic en registrarse? Es posible que encuentre varias soluciones, pero la que usaremos es $ broadcast y $ on.
$ broadcast vs $ emit
¿Qué debemos usar? $ broadcast canalizará a todos los elementos dom de children y $ emit canalizará la dirección opuesta a todos los elementos dom antecesores.
La mejor manera de evitar decidir entre $ emit o $ broadcast es canalizar desde $ rootScope y usar $ broadcast para todos sus hijos. Lo que hace que nuestro caso sea mucho más fácil, ya que nuestros elementos dom son hermanos.
Añadiendo $ rootScope y dejamos $ broadcast
app.controller(''FirstCtrl'', function($rootScope, $scope){
$scope.register = function(){
$rootScope.$broadcast(''BOOM!'', $scope.name)
}
});
Tenga en cuenta que agregamos $ rootScope y ahora estamos usando $ broadcast (broadcastName, argumentos). Para broadcastName, queremos darle un nombre único para poder capturar ese nombre en nuestro secondCtrl. ¡He elegido BOOM! solo por diversión. Los segundos argumentos ''argumentos'' nos permiten pasar valores a los oyentes.
Recibiendo nuestra transmisión
En nuestro segundo controlador, necesitamos configurar un código para escuchar nuestra transmisión
app.controller(''SecondCtrl'', function($scope){
$scope.$on(''BOOM!'', function(events, args){
console.log(args);
$scope.name = args; //now we''ve registered!
})
});
Es realmente tan simple. Ejemplo vivo
Otras formas de lograr resultados similares.
Trate de evitar el uso de este conjunto de métodos, ya que no es ni eficiente ni fácil de mantener, pero es una forma sencilla de solucionar los problemas que pueda tener.
Por lo general, puede hacer lo mismo utilizando un servicio o simplificando sus controladores. No lo discutiremos en detalle, pero pensé que solo lo mencionaría para completar.
Por último, tenga en cuenta que una emisión realmente útil para escuchar es ''$ destroy''. Puede ver que $ significa que es un método u objeto creado por los códigos de los proveedores. De todos modos, $ destroy se transmite cuando un controlador se destruye, es posible que desee escuchar esto para saber cuándo se extrae el controlador.
//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();
};
}); }());