Робота з $ range. $ Emit і $ range. $ On


887

Як я можу передати $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працювати?


6
Тільки для майбутніх читачів: не використовуйте $rootScopeдля трансляції / випромінювання, коли цього можна уникнути.
Mistalis

Відповіді:


1499

Перш за все, значення стосунку батько-дитина має значення. У вас є дві можливості випустити якусь подію:

  • $broadcast - посилає подію вниз до всіх областей дитини,
  • $emit - передає подію вгору через ієрархію діапазону.

Я нічого не знаю про ваше відношення до контролерів (областей), але є кілька варіантів:

  1. Якщо сфера 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); });
    }
    
  2. Якщо між вашими областями немає відносин батько-дитина, ви можете ввести його $rootScopeв контролер і транслювати подію на всі дочірні області (тобто також secondCtrl).

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  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в свою послугу і транслювати подію зі служби.
zbynour

13
@ Zlatko Я впевнений, що сервіси за замовчуванням не мають обсягу, і вам потрібна область для участі в системі подій. Тож вам потрібно якось надати сферу вашим послугам. $ rootScope - це найбільш загальне рішення для цього, але якщо ви хочете, щоб ваша служба надсилала події з іншої сфери, ваш контролер може передати її сферу дії сервісу, встановивши властивість на сервісі, і тепер служба може використовувати Область контролера. Більш прямою технікою може бути контролер для надання функції сервісу, до якого служба може телефонувати безпосередньо.
Оран Деннісон,

3
Якщо ви використовуєте IFRAME ця стаття буде корисною charemza.name/blog/posts/angularjs/iframe / ...
Летиція

1
Служби можуть вводити ін'єкцію $rootScope- але я хочу знати, що якщо я випускаю подію від послуги (від $rootScope), ця подія все ще буде переповнена $rootScope; ПОСЛУГА, якщо $broadcastпронизує ВНИЗ ієрархію, і $emitпронизує Вгору - що відбувається між "Вгору" та "Вниз" - оскільки мовник / емітер також є слухачем (?). Що робити, якщо я хочу, щоб подія мовчала на ВСІ "СТАРТИ" та ВСІ "ДОРОГИ", але бути "чутними" на тому ж рівні, що і диспетчер?
Коді

145

Я б також запропонував 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
У певному сенсі так, вигода полягає в тому, що ви уникаєте поширення подій.
Таліс К.

3
@ThalisK. дякую за цей варіант Це дозволяє уникнути розповсюдження, але, з іншого боку, вимагає $rootScopeвведення в контролери (що взагалі не потрібно). Але звичайно інший варіант, thx!
zbynour

77
Остерігайтеся, що $ rootScope живе вічно. Якщо ваш контролер запускається двічі, будь-який $ rootScope. $ У ньому буде запущений двічі, а захоплені події призведуть до зворотного виклику, який викликається двічі. Якщо ви замість цього використовуєте $ range. $ On, зворотний виклик буде знищений разом із контролером неявно AngularJS.
Філіп Собчак

1
Відповідно до коментаря @FilipSobczak, ви можете уникнути цієї небажаної поведінки, розв’язуючи обробника на події $ знищення, використовуючи наступний код jsfiddle.net/ndqexjsg/1
Krzysztof

111

Як я можу надсилати мій об’єкт $ range з одного контролера на інший, використовуючи. $ Emit та. $ Методами?

Ви можете надіслати будь-який об’єкт, який ви хочете, в межах ієрархії вашого додатка, включаючи $ range .

Ось коротке уявлення про те, як працюють трансляція та емісія .

Помітьте вузли нижче; всі вкладені у вузол 3. Ви використовуєте трансляцію та випромінювання, коли у вас є цей сценарій.

Примітка . Кількість кожного вузла в цьому прикладі є довільною; це легко може бути номером один; число два; або навіть число 1348. Кожне число є лише ідентифікатором для цього прикладу. Суть цього прикладу - показати вкладення кутових контролерів / директив.

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

Ознайомтесь із цим деревом. Як ви відповідаєте на наступні запитання?

Примітка. Є інші способи відповісти на ці запитання, але тут ми обговоримо трансляцію та емісію . Також, читаючи нижче тексту, припустимо, що кожне число має власний файл (директива, контролер) ex one.js, two.js, three.js.

Як вузол 1 розмовляє з вузлом 3 ?

У файлі one.js

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

У файлі three.js - самий верхній вузол для всіх дитячих вузлів, необхідних для спілкування.

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

Як вузол 2 розмовляє з вузлом 3?

У файлі two.js

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

У файлі three.js - самий верхній вузол для всіх дитячих вузлів, необхідних для спілкування.

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

Як вузол 3 розмовляє з вузлом 1 та / або вузлом 2?

У файлі three.js - самий верхній вузол для всіх дитячих вузлів, необхідних для спілкування.

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

У файлі one.js && two.js залежно від того, в якому файлі ви хочете ввести повідомлення або те і інше.

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

Як вузол 2 розмовляє з вузлом 1?

У файлі two.js

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

У файлі three.js - самий верхній вузол для всіх дитячих вузлів, необхідних для спілкування.

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

У файлі one.js

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

ЗАРАЗ

Коли у вас є всі ці вкладені дочірні вузли, які намагаються спілкуватися так, ви швидко побачите багато $ , трансляцій та $ емісій .

Ось що я люблю робити.

У самому верхньому РІЗНІ РОЗВИТКУ ( 3 у цьому випадку ...), який може бути вашим батьківським контролером ...

Отже, у файлі three.js

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

Тепер у будь-якому з дочірніх вузлів вам потрібно лише $ $ надіслати повідомлення або зафіксувати його, використовуючи $ on .

ПРИМІТКА: Зазвичай перетинати розмову в одному вкладеному контурі досить легко, не використовуючи $ emit , $ Broadcast або $ on , що означає, що більшість випадків використання є для того, щоб ви намагаєтеся отримати вузол 1 для зв'язку з вузлом 2 або навпаки.

Як вузол 2 розмовляє з вузлом 1?

У файлі two.js

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

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

У файлі three.js - самий верхній вузол для всіх дитячих вузлів, необхідних для спілкування.

Ми вже з цим справлялися, пам’ятаєте?

У файлі one.js

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

Вам все одно потрібно буде використовувати $ on з кожним конкретним значенням, яке ви хочете впіймати, але тепер ви можете створювати все, що завгодно, в будь-якому з вузлів, не турбуючись про те, як передати повідомлення через розрив батьківського вузла, коли ми вловлюємо та транслюємо загальні pushChangesToAllNodes .

Сподіваюся, це допомагає ...


як вирішити, який з них 3,2 та 1?
HIRA THAKUR

3, 2 і 1 є або вкладеними контролерами, або директивами. Створюючи додаток, пам’ятайте про своє введення та застосовуйте логіку вище. Для прикладу можна сказати, що 3 - $ rootScope програми; і все вкладено під ним. 3, 2 і 1 є довільними.
SoEzPz

Чудові приклади! Але я все ще думаю, що краще використовувати власний диспетчер подій у батьків для спілкування групи контролерів. Також корисно зберегти створення диспетчера як сервіс, щоб використовувати його як шаблон.
Денис Колодін

1
Згідно з кутовими документами на $ трансляції, The event life cycle starts at the scope on which $broadcast was called. All listeners listening for name event on this scope get notified. тому ви (як і я) отримаєте нескінченний цикл, якщо реалізуєте ctrl1, розмовляючи з ctrl2 з $on('x', function(e, data) { $broadcast('x', data) })на ctrl3. Вам потрібні ці рядки перед трансляцією; if (e.targetScope.$id === $scope.$id) { return; }
Ренато Гама

39

Для надсилання $scope objectвід одного контролера до іншого, я обговорюю про $rootScope.$broadcastі $rootScope.$emitтут, як вони використовуються найбільше.

Випадок 1 :

$ rootScope. $ трансляція: -

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

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

$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. $ emit:

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

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

Основна відмінність $ emit і $ трансляції полягає в тому, що подія $ rootScope. $ Emit потрібно прослуховувати за допомогою $ rootScope. $ On, оскільки випромінювана подія ніколи не опускається через дерево діапазону. .
У цьому випадку ви також повинні знищити слухача, як у випадку трансляції $.

Редагувати:

Я вважаю за краще не використовувати, $rootScope.$broadcast + $scope.$onа використовувати $rootScope.$emit+ $rootScope.$on. $rootScope.$broadcast + $scope.$onКомбо може викликати серйозні проблеми з продуктивністю. Це тому, що подія занепаде всіма сферами.

Редагувати 2 :

Питання, вирішене у цій відповіді, було вирішено у angular.js версії 1.2.7. $ трансляція тепер дозволяє уникнути барботажу над незареєстрованими областями і працює так само швидко, як $ 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); });
        }
}

Події, пов'язані з об'єктом $ range, просто працюють у контролері власника. Зв'язок між контролерами здійснюється через $ rootScope або Services.


7

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

        }

    }])

4

Це моя функція:

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

4
<!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>

2

Область застосування може використовуватися для розповсюдження, передачі події дітям або батькам.

$ emit - поширює подію на батьків. $ трансляція - поширює подію дітям. $ 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>

приклад app.js :

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

Тут ви можете перевірити код: http://jsfiddle.net/zp6v0rut/41/


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/


0

Згідно з документами подій angularjs, кінець прийому повинен містити аргументи зі структурою на зразок

@params

- {Object} подія - це об'єкт події, що містить інформацію про подію

- {Object} аргументи, які передає виклик (Зверніть увагу, що це може бути лише один, так що краще надсилати об’єкт словника завжди)

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

Крім того, якщо ви намагаєтеся отримати спільну інформацію, яка буде доступна для різних контролерів, є ще один спосіб досягти цього, а це - кутові послуги. Оскільки послуги є одиночними, інформація може зберігатися та отримуватись через контролери. Просто створіть геть і функції встановлення в цій службі, розкривають ці функції, вносять глобальні змінні в сервіс і використовують їх для зберігання інформації


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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.