Работа с $ scope. $ Emit и $ scope. $ On

806

Как я могу отправить свой объект $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?

  • 5
    Только для будущих читателей: не используйте $rootScope для широковещательной передачи / передачи, когда этого можно избежать.
Теги:

13 ответов

1435

Прежде всего, отношение родительско-дочерних объектов имеет значение. У вас есть две возможности испускать какое-то событие:

  • $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]);
    }
    
  • 8
    Есть ли способ передать событие из службы в контроллер?
  • 29
    Да, теоретически вы можете $rootScope в ваш сервис и передать событие из сервиса.
Показать ещё 14 комментариев
134

Я бы предложил 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
    Это тогда будет в основном служить в качестве центральной шины событий правильно?
  • 5
    В некотором смысле, да, преимущество в том, что вы избегаете распространения событий.
Показать ещё 5 комментариев
106

Как я могу отправить объект $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.

Надеюсь, что это поможет...

  • 0
    как решить какой из 3,2 и 1?
  • 0
    3, 2 и 1 являются либо вложенными контроллерами, либо директивами. Создавая свое приложение, имейте в виду свое вложение и применяйте приведенную выше логику. Например, мы можем сказать, что 3 - это $ rootScope приложения; и все вложено ниже этого. 3, 2 и 1 произвольны.
Показать ещё 4 комментария
27

Чтобы отправить объект $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.

10

Вы должны использовать $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.

5

Вы можете вызвать службу у своего контроллера, которая возвращает обещание, а затем использовать его в своем контроллере. И далее используйте $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);
        });

       }


    }])
3
<!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>
3

Это моя функция:

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

$rootScope.$on('setTitle', function(event, title) {
    if (scope.item) 
        scope.item.name = title;
    else 
        scope.item = {name: title};
});
  • 1
    Я думаю, что это плохая практика, так как ваш rootScope будет загроможден. См. Stackoverflow.com/questions/24830679/…
2

В итоге я добавил внешнюю библиотеку EventEmitter для проектирования в качестве службы и ввода ее туда, где мне нужно. Поэтому я могу "испускать" и "on" что угодно, не заботясь о наследовании области. Это меньше проблем и, конечно же, более высокая производительность. Также более читабельны для меня.

Поддержка подстановочных знаков: EventEmitter2

Хорошая производительность: eventemitter3

Другая альтернатива: Drip

2

Ниже код показывает два субконтроллера, из которых события отправляются вверх в родительский контроллер (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/

1

Область (области) может использоваться для распространения, отправки события в дочерние объекты области или родителя.

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

0

Самый простой способ:

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

В соответствии с событием angularjs docs принимающая сторона должна содержать аргументы со структурой вроде

@params

- {Object} событие, являющееся объектом события, содержащим информацию о событии

- {Object} args, которые передаются вызываемым пользователем (обратите внимание, что это может быть только одно, поэтому лучше отправлять объект словаря всегда)

$scope.$on('fooEvent', function (event, args) { console.log(args) }); Из вашего кода

Кроме того, если вы пытаетесь получить доступную общую информацию для разных контроллеров, есть еще один способ достичь этого, а это angular services.Since, поскольку сервисы представляют собой информацию о синглонах, можно сохранять и извлекать через контроллеры. Просто создайте функции getter и setter в этой службе, выставьте эти функции, сделайте глобальные переменные в службе и используйте их для хранения информации

Ещё вопросы

Сообщество Overcoder
Наверх
Меню