Как создать пользовательское событие в службе AngularJs

Я работаю над проектом AngularJs. У меня есть служба, которая устанавливает и удаляет события на некоторых кнопках. Эта служба используется другой службой, которую я не хочу напрямую взаимодействовать с кнопками. Однако я хотел бы, чтобы событие нажатия кнопки было отфильтровано через первую службу и обработано во второй. Поскольку я не хочу, чтобы вторая служба знала о кнопках, я полагаю, что мне нужно будет создать пользовательское событие в первой службе. Как я могу создать пользовательское событие и запускать его при нажатии кнопки?

Заранее спасибо.


person rmg.n3t    schedule 09.06.2014    source источник
comment
Возможно, шаблон наблюдателя предлагает другие решения проблемы scotch.io/bar-talk/   -  person William Ardila    schedule 22.12.2016


Ответы (3)


Если вы хотите отправить событие между службами/директивами, используйте broadcast:

$rootScope.$broadcast('buttonPressedEvent');

И получить это так:

$rootScope.$on('buttonPressedEvent', function () {
             //do stuff
        })
person Chancho    schedule 09.06.2014
comment
Привет, большое спасибо. Однако должна ли сама служба запускать событие таким образом, чтобы для его обработки вторая служба должна была ссылаться на первую? Например: внутри службы2 будет строка кода: service1.eventfired = do_something(). - person rmg.n3t; 10.06.2014
comment
Да, это последняя часть моего ответа. во втором сервисе вам нужно добавить этот код, просто измените $scope.$on на $rootScope.$on - person Chancho; 10.06.2014
comment
Это намного чище, чем то, что я рассматривал. Ура вам и ура $rootscope.$broadcast()! - person rinogo; 14.09.2016

Любая глобальная интеграция на основе области действия повредит пространству имен и может привести к ужасным побочным эффектам в приложениях среднего и большого размера. Я рекомендую немного более сложное, но определенно более чистое решение с использованием прокси-сервиса.

<сильный>1. Создать прокси-сервис

angular.module('app').service('userClickingHelper', [
  function() {
    var listeners = [];
    return {
      click: function(args) {
        listeners.forEach(function(cb) {
          cb(args);
        });
      },
      register: function(callback) {
        listeners.push(callback);
      }
    };
  }
]);

<сильный>2. Создайте директиву кнопки, которая использует userClickingHelper в качестве зависимости.

angular.module('app').directive('onDistributedClick', ['userClickingHelper', function (userClickingHelper) {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.on('click', userClickingHelper.click);
        }
    };
}]);

<сильный>3. Зарегистрируйте несвязанный сервис с использованием прокси-сервера.

angular.module('app').service('myUnrelatedService', [function (userClickingHelper) {
    userClickingHelper.register(function(){
        console.log("The button is clicked somewhere");
    });
}]);

В результате получается изолированная область распространения событий, но ни директива, ни служба не знают друг о друге. Также проще проводить модульное тестирование.

Я использую аналогичное решение для глобально доступного модального режима «Загрузка», поэтому я могу абстрагироваться от того, как контроллер/служба говорит «пользователь не должен нажимать или что-либо прямо сейчас».

person Mano Kovacs    schedule 09.04.2015
comment
+1. Этот ответ обеспечивает общую хорошую практику при реализации слушателей/обработчиков, тогда как ответ Chancho больше адаптирован к варианту использования OP. - person Yatit Thakker; 09.11.2017
comment
Мне понравился этот подход, так как мы можем перехватить уведомление из надежного источника или знаем, откуда оно должно прийти. Если мы используем $rootScope.$broadcast, то в сложном приложении высока вероятность того, что кто-то будет перекрывать одно и то же событие для трансляции своих данных. - person Aamol; 12.09.2018

Вы можете создать и создать событие со следующим на вашем элементе

ng-click="$emit('customEvent')"

Затем в вашем контроллере вы можете использовать

$rootScope.$on('customEvent', function(){
    // do something
})

Демо

person Jonathan de M.    schedule 09.06.2014
comment
Я хочу, чтобы две «службы» общались не с представлением, а с контроллером. Однако, прочитав ваш ответ, я получил своего рода прозрение. Я мог бы просто установить двустороннюю связь между службами. Когда служба 1 фиксирует событие нажатия кнопки, она может вызвать требуемый метод в службе два, который выполнит требуемую обработку. Кажется, это простой способ добиться того, что мне нужно. Большое спасибо! - person rmg.n3t; 10.06.2014
comment
Сотрите это! Я бы тесно связал эти два сервиса вместе! Я буду использовать методы $rootScope.$on() и $rootScope.$broadcast(), указанные другим пользователем. Спасибо еще раз! (И если вам интересно, да, я новичок)! - person rmg.n3t; 10.06.2014
comment
на самом деле он делает то же самое, моя демонстрация имеет функции вещания и испускания, я использовал сэмит для демонстрации, мой подход состоял в том, чтобы эмитировать непосредственно из DOM, а не добавлять больше логики в контроллер - person Jonathan de M.; 10.06.2014
comment
Этот ответ нуждается в большем количестве голосов! Для моих нужд больше подходит $rootScope.$broadcast(), но я вижу, что в некоторых ситуациях лучше использовать ng-click="$emit('customEvent')". - person rinogo; 14.09.2016