Работа с $scope. $Emit и $scope. $On
Как я могу отправить свой объект $scope
с одного контроллера на другой с помощью методов .$emit
и .$on
?
function firstCtrl($scope) {
$scope.$emit('someEvent', [1,2,3]);
}
function secondCtrl($scope) {
$scope.$on('someEvent', function(mass) { console.log(mass); });
}
Это не работает так, как мне кажется. Как работают $emit
и $on
?
Ответы
Ответ 1
Прежде всего, отношение родительско-дочерних объектов имеет значение. У вас есть две возможности испускать какое-то событие:
-
$broadcast
- отправляет событие вниз во все дочерние области,
-
$emit
- отправляет событие вверх по иерархии областей.
Я ничего не знаю о отношении ваших контроллеров (scopes), но есть несколько вариантов:
-
Если область firstCtrl
является родителем области secondCtrl
, ваш код должен
замените $emit
на $broadcast
в firstCtrl
:
function firstCtrl($scope)
{
$scope.$broadcast('someEvent', [1,2,3]);
}
function secondCtrl($scope)
{
$scope.$on('someEvent', function(event, mass) { console.log(mass); });
}
-
Если между вашими областями нет отношения родитель-ребенок,
может вводить $rootScope
в контроллер и транслировать событие
ко всем дочерним областям (т.е. также secondCtrl
).
function firstCtrl($rootScope)
{
$rootScope.$broadcast('someEvent', [1,2,3]);
}
-
Наконец, когда вам нужно отправить событие из дочернего контроллера
для областей вверх вы можете использовать $scope.$emit
. Если область firstCtrl
является родительской для области secondCtrl
:
function firstCtrl($scope)
{
$scope.$on('someEvent', function(event, data) { console.log(data); });
}
function secondCtrl($scope)
{
$scope.$emit('someEvent', [1,2,3]);
}
Ответ 2
Я бы предложил 4-й вариант в качестве лучшей альтернативы предлагаемым опциям @zbynour.
Используйте $rootScope.$emit
, а не $rootScope.$broadcast
, независимо от отношения между диспетчером и контроллером приема. Таким образом, событие остается в пределах набора $rootScope.$$listeners
, тогда как при $rootScope.$broadcast
событие распространяется на все дочерние области, большинство из которых, вероятно, не будут слушателями этого события. И, конечно, в конце приемника контроллера вы просто используете $rootScope.$on
.
Для этого параметра вы должны помнить об уничтожении слушателей rootScope контроллера:
var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
unbindEventHandler();
});
Ответ 3
Как я могу отправить объект $scope с одного контроллера на другой, используя методы $emit и. $on?
Вы можете отправить любой объект, который вы хотите, в иерархию вашего приложения, включая $scope.
Вот краткое представление о том, как работают трансляция и emit.
Обратите внимание на узлы ниже; все вложенные в node 3. При использовании этого сценария вы используете трансляцию и emit.
Примечание: Число каждого node в этом примере произвольно; он может легко быть номером один; номер два; или даже номер 1 348. Каждый номер является только идентификатором для этого примера. Цель этого примера - показать вложенность контроллеров Angular/директив.
3
------------
| |
----- ------
1 | 2 |
--- --- --- ---
| | | | | | | |
Посмотрите это дерево. Как вы отвечаете на следующие вопросы?
Примечание. Есть другие способы ответить на эти вопросы, но здесь мы обсудим трансляцию и emit. Кроме того, при чтении ниже текста предположим, что у каждого номера есть собственный файл (директива, контроллер) e.x. one.js, two.js, three.js.
Как node 1 разговаривать с node 3?
В файле one.js
scope.$emit('messageOne', someValue(s));
В файле three.js - самый верхний node для всех дочерних узлов, необходимых для связи.
scope.$on('messageOne', someValue(s));
Как node 2 разговаривать с node 3?
В файле two.js
scope.$emit('messageTwo', someValue(s));
В файле three.js - самый верхний node для всех дочерних узлов, необходимых для связи.
scope.$on('messageTwo', someValue(s));
Как node 3 разговаривают с node 1 и/или node 2?
В файле three.js - самый верхний node для всех дочерних узлов, необходимых для связи.
scope.$broadcast('messageThree', someValue(s));
В файле one.js && & two.js какой файл вы хотите поймать сообщение или и то, и другое.
scope.$on('messageThree', someValue(s));
Как node 2 разговаривают с node 1?
В файле two.js
scope.$emit('messageTwo', someValue(s));
В файле three.js - самый верхний node для всех дочерних узлов, необходимых для связи.
scope.$on('messageTwo', function( event, data ){
scope.$broadcast( 'messageTwo', data );
});
В файле one.js
scope.$on('messageTwo', someValue(s));
ОДНАКО
Когда у вас есть все эти вложенные дочерние узлы, пытающиеся общаться так, вы быстро увидите много $, $трансляции и $emit's.
Вот что мне нравится делать.
В самом верхнем PARENT node ( 3 в этом случае...), который может быть вашим родительским контроллером...
Итак, в файле three.js
scope.$on('pushChangesToAllNodes', function( event, message ){
scope.$broadcast( message.name, message.data );
});
Теперь в любом из дочерних узлов вам потребуется только $emit сообщение или поймать его с помощью $on.
ПРИМЕЧАНИЕ.. Как правило, довольно легко перекрестно говорить по одному вложенному пути, не используя $emit, $broadcast или $on, что означает большинство случаев использования, когда вы пытаетесь получить node 1 для связи с node 2 или наоборот.
Как node 2 разговаривают с node 1?
В файле two.js
scope.$emit('pushChangesToAllNodes', sendNewChanges());
function sendNewChanges(){ // for some event.
return { name: 'talkToOne', data: [1,2,3] };
}
В файле three.js - самый верхний node для всех дочерних узлов, необходимых для связи.
Мы уже справлялись с этим, помним?
В файле one.js
scope.$on('talkToOne', function( event, arrayOfNumbers ){
arrayOfNumbers.forEach(function(number){
console.log(number);
});
});
Вам все равно нужно использовать $на с каждым конкретным значением, которое вы хотите поймать, но теперь вы можете создавать все, что угодно, в любом из узлов, не беспокоясь о том, как получить сообщение через родительский разрыв node, поскольку мы обнаруживаем и транслируем общие pushChangesToAllNodes.
Надеюсь, что это поможет...
Ответ 4
Чтобы отправить объект $scope с одного контроллера на другой, я буду обсуждать здесь $rootScope.$broadcast
и $rootScope.$emit
, поскольку они используются больше всего.
Случай 1:
$rootScope $широковещательного: -.
$rootScope.$broadcast('myEvent',$scope.data);
$rootScope.$on('myEvent', function(event, data) {}
$rootScope
прослушиватель не уничтожается автоматически. Вам нужно уничтожить его, используя $destroy
. Лучше использовать $scope.$on
, поскольку слушатели на $scope
будут уничтожены автоматически, то есть как только будет уничтожена область $.
$scope.$on('myEvent', function(event, data) {}
Или
var customeEventListener = $rootScope.$on('myEvent', function(event, data) {
}
$scope.$on('$destroy', function() {
customeEventListener();
});
Случай 2:
$rootScope $выделяют:.
$rootScope.$emit('myEvent',$scope.data);
$rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works
Основное отличие в $emit и $broadcast заключается в том, что $rootScope. $emit event нужно прослушивать с помощью $rootScope. $on, потому что испускаемое событие никогда не спускается через дерево областей..
В этом случае вы также должны уничтожить слушателя, как в случае $broadcast.
Edit:
Я предпочитаю не использовать $rootScope.$broadcast + $scope.$on
, но использовать $rootScope.$emit+ $rootScope.$on
. Компонента $rootScope.$broadcast +
$scope.$on
может вызвать серьезные проблемы с производительностью. То есть потому что событие будет всплывать во всех областях.
Изменить 2:
Проблема, рассмотренная в этом ответе, решена в angular.js версия 1.2.7. $broadcast теперь позволяет избежать пузырьков по незарегистрированным областям и работает так же быстро, как $emit.
Ответ 5
Вы должны использовать $rootScope для отправки и захвата событий между контроллерами в одном приложении. Ввести $rootScope зависимость от ваших контроллеров. Вот рабочий пример.
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); });
}
}
События, связанные с объектом $scope, работают только в контроллере владельца. Связь между контроллерами осуществляется через $rootScope или Services.
Ответ 6
Вы можете вызвать службу у своего контроллера, которая возвращает обещание, а затем использовать его в своем контроллере. И далее используйте $emit или $broadcast для информирования других контроллеров об этом.
В моем случае мне пришлось сделать http-звонки через мою службу, поэтому я сделал что-то вроде этого:
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
})
}
и мой сервис выглядит следующим образом
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);
});
}
}])
Ответ 7
Это моя функция:
$rootScope.$emit('setTitle', newVal.full_name);
$rootScope.$on('setTitle', function(event, title) {
if (scope.item)
scope.item.name = title;
else
scope.item = {name: title};
});
Ответ 8
<!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>
Ответ 9
Ниже код показывает два субконтроллера, из которых события отправляются вверх в родительский контроллер (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/
Ответ 10
В итоге я добавил внешнюю библиотеку EventEmitter для проектирования в качестве службы и ввода ее туда, где мне нужно. Поэтому я могу "испускать" и "on" что угодно, не заботясь о наследовании области. Это меньше проблем и, конечно же, более высокая производительность. Также более читабельны для меня.
Поддержка подстановочных знаков: EventEmitter2
Хорошая производительность: eventemitter3
Другая альтернатива: Drip
Ответ 11
Область (области) может использоваться для распространения, отправки события в дочерние объекты области или родителя.
$emit - распространяет событие на родителя. $broadcast - распространяет событие на детей.
$on - метод для прослушивания событий, распространяемый с помощью $emit и $broadcast.
example 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>
example app.js:
angular.module('appExample', [])
.controller('EventCtrl', ['$scope', function($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}]);
Здесь вы можете проверить код:
http://jsfiddle.net/zp6v0rut/41/
Ответ 12
В соответствии с событием angularjs docs принимающая сторона должна содержать аргументы со структурой вроде
@params
- {Object} событие, являющееся объектом события, содержащим информацию о событии
- {Object} args, которые передаются вызываемым пользователем (обратите внимание, что это может быть только одно, поэтому лучше отправлять объект словаря всегда)
$scope.$on('fooEvent', function (event, args) { console.log(args) });
Из вашего кода
Кроме того, если вы пытаетесь получить доступную общую информацию для разных контроллеров, есть еще один способ достичь этого, а это angular services.Since, поскольку сервисы представляют собой информацию о синглонах, можно сохранять и извлекать через контроллеры. Просто создайте функции getter и setter в этой службе, выставьте эти функции, сделайте глобальные переменные в службе и используйте их для хранения информации
Ответ 13
Самый простой способ:
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>