Давным-давно я написал статью о работе с EventManager в Angular. В ней я рассказал, как можно сохранить привычный нам синтаксис подписок на события, при этом избежав лишних запусков проверки изменений на частых и чувствительных событиях. Однако описанный мною метод громоздкий и сложный для восприятия. Пришло время переписать фильтрацию на декораторы.  Для тех, кто не читал и не хочет читать прошлую статью, краткое изложение проблемы: В прошлой статье я предлагал механизм фильтрации событий с возможностью при подписке отменить действие браузера по умолчанию или остановить всплытие события. В этот раз мы доведем данный подход до рабочего кода. Его можно подключать к проекту и использовать с минимумом дополнительных телодвижений. Для настройки обработки будем использовать модификаторы имени события аналогично встроенным в Angular псевдособытиям нажатия клавиш (keydown.ctrl.enter и тому подобные).  Вспомним, как работает EventManager. В момент создания он собирает имеющиеся плагины. В Angular заложено несколько стандартных плагинов, а добавить свои можно благодаря внедрению зависимостей через EVENT_MANAGER_PLUGINS мультитокен. При подписке на событие он находит подходящий плагин, спрашивая все по очереди, поддерживают ли они событие с таким именем. Затем он вызывает метод addEventListener подходящего плагина, передавая в него имя события, элемент, на котором мы его слушаем, и обработчик, который нужно вызвать. Назад плагин возвращает метод для удаления подписки. Начнем с preventDefault и stopPropagation. Создадим пару плагинов, которые, получив на вход имя события и обработчик, выполнят свою задачу и передадут обработку дальше: Задачу пропуска событий решить несколько сложнее. По сути, она состоит из трех составляющих: С первым пунктом отлично справится плагин, так как у него есть доступ к NgZone и запустить обработчик вне зоны очень просто: Для второго и третьего пунктов используем декоратор, фильтрующий вызов метода. Создадим фабрику, которая будет получать на вход функцию-фильтр. Мы сможем выполнять ее в контексте инстанса нашего компонента/директивы, так что у нас будет доступ к this. Однако часто нужно изучить само событие, чтобы понять, нужно ли на него реагировать. Самый простой способ получить доступ к нему для нас — вызывать функцию-фильтр с теми же аргументами, что и метод, на который мы вешаем декоратор. Тогда останется только передавать $event в обработчик события в шаблоне или @HostListener. Код декоратора с использованием фильтра будет выглядеть следующим образом: Так мы избежим лишних вызовов. Но если фильтр даст зеленый свет и обработчик выполнится — нужно как-то сообщить Angular, что необходимо запустить проверку изменений. Когда выйдет Angular 10 и Ivy стабилизируется и станет доступным для библиотек, будет достаточно вызывать markDirty(this). Но пока этого не случилось, нам нужно как-то добраться до NgZone. Для этого запилим временный хак. Как мы помним, доступ к зоне есть у плагинов. Напишем специальный плагин, который пришлет NgZone к нам, а декоратор ее перехватит: Единственная задача этого плагина — слушать подписку на событие с модификатором .init и передавать в обработчик зону, как только она стабилизируется (иными словами, когда компонент соберется). Наш декоратор будет использоваться вместе с @HostListener(‘prop.init’, [‘$event’]) и будет ловить зону: Конечно, это хак. Но можно утешиться тем, что это временное решение и оно работает. Остается дождаться дивного нового мира Ivy.  Демо из прошлой статьи, переработанное на новый подход, можно изучить тут:
https://stackblitz.com/edit/angular-event-filter-decorator Помните, что для АОТ компиляции функции, которые передаются в фабрики декораторов, выносятся в отдельные экспортируемые сущности. В качестве простейшего примера сделаем компонент, который показывает список и подгружает новые элементы, когда он полностью прокручен вниз. В шаблоне будет async пайп на Observable из элементов: В коде компонента добавим сервис, имитирующий запросы на сервер за новыми элементами и подписку на событие скролла с фильтрацией: Вот и все. Посмотреть работу в действии можно тут:
https://stackblitz.com/edit/angular-event-filters-scroll Обратите внимание на консоль, в которой выводится сообщение на каждый цикл проверки изменений. Весь этот код будет работать и с произвольными CustomEventами, которые создаются и диспатчатся руками. Синтаксис при этом никак не изменится. Описанное решение вынесено в крошечную (1 КБ gzip) open-source-библиотеку под названием @tinkoff/ng-event-filters. К релизу Angular 10 выпустим версию 2.0.0, в которой перейдем на markDirty(this), а текущий код работает даже с Angular 4. Исходный код npm-пакет Google Developer Expert | Angular