$ on і $ транслюються у куті


282

У мене є footerController та codeScannerController з різними видами.

angular.module('myApp').controller('footerController', ["$scope", function($scope) {}]);

angular.module('myApp').controller('codeScannerController', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...

Коли я натискаю на <li>в footer.html, я повинен отримати цю подію в codeScannerController.

<li class="button" ng-click="startScanner()">3</li>

Я думаю , що це може бути реалізовано $onі $broadcast, але я не знаю , як і не може знайти приклади де завгодно.

Відповіді:


631

Якщо ви хочете $broadcastскористатися $rootScope:

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}

А потім для отримання використовуйте $scopeконтролер:

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});

Якщо ви хочете, ви можете передавати аргументи, коли $broadcast:

$rootScope.$broadcast('scanner-started', { any: {} });

А потім отримайте їх:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});

Документація для цього всередині Документів Досьє .


2
Ви можете назвати подію чим завгодно.
Давін Тріон

5
Переконайтеся, що ви маєте область $. $ Apply (); ваші зміни!
Ісмаїл

4
@Ismail Чому ... і куди?
Яанс

7
Чи є якісь рекомендовані практики зберігання цих рядків десь, а не жорстке кодування трансляційного повідомлення?
rperryng

8
@Ismail $scope.$apply()необхідний лише при зміні моделі за межами кутової рамки (як, наприклад, у setTimeout, зворотній діалог або зворотний виклик ajax), іншими словами $apply(), вже запускається після завершення всього коду в .$on().
th3uiguy

97

По- перше, короткий опис $on(), $broadcast()і$emit() :

  • .$on(name, listener) - Слухає певну подію за певною датою name
  • .$broadcast(name, args)- Трансляція події вниз на $scopeвсіх дітей
  • .$emit(name, args)- Визначте подію за $scopeієрархією всім батькам, включаючи$rootScope

На основі наступного HTML (див. Повний приклад тут ):

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

Розгорнуті події пройдуть $scopesнаступне:

  • Трансляція 1 - Переглядатиме лише Контролер 1 $scope
  • Випромінювання 1 - $scopeпотім побачить контролер 1$rootScope
  • Трансляція 2 - Ви побачите Контролер 2, $scopeа потім Контролер 3$scope
  • Випромінювання 2 - $scopeпотім побачить контролер 2$rootScope
  • Трансляція 3 - Переглядатиме лише Контролер 3 $scope
  • Випромінювання 3 - Видно буде Controller 3 $scope, Controller 2 $scopeтоді$rootScope
  • Broadcast Root - буде розглядатися $rootScopeі $scopeвсі контролери (1, 2 , то 3)
  • Випромінювати корінь - побачить лише о $rootScope

JavaScript для запуску подій (знову ж, ви можете побачити робочий приклад тут ):

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');
    });
}]);

як я можу уявити ієрархію свого додатка на прикладі, який ви навели. Як контролером може бути батько чи дитина. ?? Що я намагаюся сказати, це те, що у мене є ряд станів, наприклад. LoginCtrl -> homeCrl -> notifikacijaCtrl тощо.
HIRA THAKUR

26

Одне, що вам слід знати, - префікс $ стосується кутового методу, префікси $$ - це кутові методи, яких вам слід уникати.

нижче - приклад шаблону та його контролерів, ми вивчимо, як $ Broadcast / $ on може допомогти нам досягти того, що ми хочемо.

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

Контролери є

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});

Моє запитання до вас - як ви передаєте ім'я другому контролеру, коли користувач натискає реєстрацію? Ви можете придумати декілька рішень, але тим, що ми будемо використовувати, є використання $ Broadcast та $ on.

$ трансляція проти $ емісія

Яку нам використовувати? $ трансляція буде спрямовуватися до всіх елементів дитячого дому, а $ emit буде спрямовувати протилежний напрям до всіх елементів дому предка.

Найкращий спосіб уникнути вирішення між $ emit або $ Broadcast - це канал з $ rootScope та використання $ мовлення для всіх його дітей. Що значно полегшує наш випадок, оскільки елементи нашого дому - це брати і сестри.

Додавання $ rootScope і дозволяє $ мовлення

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});

Зверніть увагу, що ми додали $ rootScope і тепер використовуємо $ Broadcast (BroadName, аргументи). Для BroadName ми хочемо дати йому унікальну назву, щоб ми могли зловити це ім’я в нашому secondCtrl. Я вибрав БУМ! задля розваги. Другий аргумент «аргументи» дозволяє нам передавати значення слухачам.

Отримання нашого мовлення

У другому контролері нам потрібно встановити код, щоб слухати нашу трансляцію

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});

Це дійсно так просто. Живий приклад

Інші способи досягнення подібних результатів

Постарайтеся уникати використання цього набору методів, оскільки це не є ні ефективним, ні простим у обслуговуванні, але це простий спосіб виправити неполадки.

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

Нарешті, пам’ятайте, що насправді корисна трансляція - «знищити» знову, ви можете побачити $ означає, що це метод або об’єкт, створений кодами постачальників. У будь-якому випадку $ знищається, коли контролер знищується, ви можете послухати це, щоб знати, коли ваш контролер видалений.


2
Як попередження, постарайтеся не використовувати занадто багато трансляцій / випромінювань у вашому додатку. Їм дуже важко керувати, особливо у великому додатку, оскільки відстежувати коріння цих подій є дуже важким завданням.
Ян Лі

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