4 способа прослушивания событий в Angular
Иногда нам нужно отреагировать на определенные события в браузере и написать против них код. Возможно, нам нужно услышать щелчок, изменение ввода, фокус или размытие. Возможно, нам нужно сделать что-то вроде прослушивания щелчка в любом месте документа. Что ж, хорошие новости: в Angular есть много способов сделать это. В этом посте я собираюсь показать вам четыре распространенных способа.
- Сначала мы будем использовать метод, называемый привязкой событий.
- Далее мы воспользуемся декоратором
@HostListener
. - После этого мы будем использовать Angular
@Output
иEventEmitter
. - И, наконец, мы воспользуемся
Renderer2
классом и егоlisten()
методом.
Хорошо, давайте займёмся этим!
Использование привязки событий Angular
В Angular привязка событий используется в самых простых случаях, и мы, вероятно, захотим использовать ее почти как сценарий по умолчанию каждый раз, когда нам нужно прослушивать события в элементе. Только если привязка событий нам не подходит, нам следует обратиться к чему-то другому.
Привязку событий в Angular настроить довольно просто, мы просто используем круглые скобки и любое необходимое нам событие. В этом случае мы собираемся привязаться к событию фокуса. И когда мы фокусируемся в нашем текстовом поле, мы просто хотим поместить строковое значение, input focus
, в наш массив сообщений в этом компоненте.
<input
...
(focus)="messages.push('input focus')" />
Теперь, когда мы фокусируемся, мы видим, что срабатывает событие. Затем, когда мы снова фокусируемся, событие продолжает срабатывать.
Мы также можем добавить и другие события, а как насчет события размытия?
<input
...
(blur)="messages.push('input blur')" />
Мы даже можем делать такие вещи, как прослушивание события ввода в нашем текстовом поле. Итак, если мы добавим значение, каждый раз, когда мы нажимаем клавишу, мы увидим событие input change
.
<input
...
(input)="messages.push('input input')" />
А что, если нам нужно привязаться к событию на узле директивы или компонента? Что ж, в Angular у нас есть декоратор @HostListener
, который мы можем использовать для подобных вещей.
Использование декоратора @HostListener для директивы
Хорошо, в этом примере, чтобы продемонстрировать, как @HostListener
работает, я добавил эту appHostListener
директиву к нашей кнопке.
<button appHostListener>
Submit
</button>
В этой директиве мы собираемся прослушивать события нажатия на самой кнопке. Но мы хотим делать это каждый раз, когда применяем эту директиву, поэтому в данном случае мы собираемся использовать наше событие @HostListener
.
Итак, давайте зайдем в директиву и добавим наш декоратор @HostListener
. Нам нужно убедиться и импортировать это из Angular Core. Затем мы свяжем это событие щелчка прямо в нашем декораторе и передадим наше событие с помощью файла $event
. Мы назовем нашу функцию handleHostClick()
, и внутри нее будет событие типа PointerEvent
.
import { ..., HostListener } from '@angular/core';
@Directive({selector: '[appHostListener]'})
export class HostListenerDirective {
@HostListener('click', ['$event']) handleHostClick(event: PointerEvent) {
}
}
Теперь в этом прослушивателе, чтобы предотвратить отправку формы при нажатии этой кнопки, давайте добавим preventDefault()
, а затем добавим оповещение при нажатии кнопки.
@HostListener('click', ['$event']) handleHostClick(event: PointerEvent) {
event.preventDefault();
alert('Button Clicked!');
}
Хорошо, давайте посмотрим, что произойдет.
И вот, срабатывает предупреждение с надписью «Button Clicked!» сообщение.
Итак, что, если бы мы действительно хотели отреагировать на тот факт, что наша кнопка была нажата, и сделать то же самое, что мы делаем, когда срабатывают события ввода? Итак, когда нажимается наша кнопка, мы хотим добавить ее в наш массив сообщений.
Что ж, у нас есть способ сделать это из нашей директивы. Мы можем создать собственное событие, используя Angular @Output
и EventEmitter
.
Использование пользовательского события с помощью @Output и EventEmitter
Хорошо, мы добавим @Output
и EventEmitter
в нашу директиву прослушивателя хоста. Для этого давайте начнем с добавления @Output
. Он также исходит из Angular Core, поэтому нам нужно убедиться, что он импортирован. Мы назовем этот вывод «buttonClick» и присвоим ему значение new EventEmitter
, которое будет генерировать PointerEvent
. EventEmitter
также необходимо импортировать из Angular Core.
import { ..., Output, EventEmitter } from '@angular/core';
@Directive({selector: '[appHostListener]'})
export class HostListenerDirective {
@Output() buttonClick = new EventEmitter<PointerEvent>();
}
Теперь в нашей функции HostListener
вместо оповещения о нажатии кнопки мы будем генерировать событие buttonClick
.
@HostListener('click', ['$event']) handleHostClick(event: PointerEvent) {
...
this.buttonClick.emit();
}
Теперь нам нужно подключить это buttonClick
событие. Возвращаясь к нашему примеру шаблона компонента для нашей кнопки, мы подключим пользовательское событие и, когда это произойдет, добавим в наш список новое сообщение о нажатии кнопки.
<button appHostListener (buttonClick)="messages.push('button click')">
Submit
</button>
Хорошо, теперь давайте посмотрим, что произойдет, когда мы нажмем кнопку.
И вот, наше пользовательское событие теперь срабатывает и правильно добавляет сообщение в список.
Использование Renderer2 listen() метода
Хорошо, теперь на этот раз мы хотим прослушивать события щелчков по нашему документу в целом и реагировать на них. Итак, как мы можем это сделать? Что ж, мы можем использовать класс Renderer2
, потому что он имеет возможность принимать любой элемент и прослушивать любое событие, возникающее на этом элементе. Итак, давайте посмотрим, как мы это сделаем.
Поскольку мы хотим прослушивать эти глобальные клики в этом примере компонента только тогда, когда он находится на странице, мы собираемся сделать это прямо из этого компонента, что делает Renderer2
идеальным кандидатом для того, что мы пытаемся сделать.
Для начала нам нужно импортировать Renderer2
и предоставить его в формате constructor
. Нам также понадобится наш ngOnInit()
метод и наш ngOnDestroy()
метод.
import { Component, OnDestroy, OnInit, Renderer2 } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css'],
})
export class ExampleComponent implements OnInit, OnDestroy {
constructor(private renderer: Renderer2) {}
}
Теперь мы добавим переменную для нашей функции bodyClickListener
и напечатаем ее как функцию void
.
export class ExampleComponent implements OnInit, OnDestroy {
private bodyClickListener?: () => void;
...
}
Теперь мы установим это с помощью функции Renderer2
и listen()
. Первый параметр, который принимает эта функция прослушивания, — это элемент, который мы хотим прослушивать, поэтому в данном случае это будет document.body
. Следующий параметр — это событие, которое мы хотим прослушивать, в данном случае это будет событие click
. И затем у нас есть обратный вызов, который мы хотим запускать каждый раз, когда срабатывает это событие. Для этого мы хотим поместить сообщение «body click» в наш массив сообщений.
ngOnInit() {
this.bodyClickListener = this.renderer.listen(
document.body,
'click',
(event) => {
this.messages.push('body click');
}
);
}
Хорошо, как мы справились?
Итак, щелчок в любом месте тела запускает событие.
Теперь, делая это, нам также необходимо убедиться, что при уничтожении этого компонента мы правильно очищаем прослушиватель событий, чтобы избежать проблем с производительностью и утечек памяти. Мы делаем это внутри ngOnDestroy
метода, и если наш bodyClickListener
определен, нам просто нужно вызвать функцию void
.
ngOnDestroy() {
if (this.bodyClickListener) {
this.bodyClickListener();
}
}
Теперь это будет правильно очищено при уничтожении компонента и предотвратит любые утечки памяти.
Итак, теперь у нас есть 4 разных способа прослушивания событий в Angular. Во-первых, у нас есть привязка классов для более стандартных случаев, когда нам просто нужно отреагировать на событие в элементе. Затем у нас есть @HostListener
декоратор, который позволяет нам прослушивать события в host
элементе наших компонентов и директив. Затем мы можем добавить наши собственные события с помощью @Output
и EventEmitter
. И, наконец, мы можем использовать этот Renderer2
метод listen()
, если больше ничего не помогает.
Надеемся, что эти примеры дадут вам несколько дополнительных возможностей для сборки в Angular.
Хотите увидеть это в действии?
Ознакомьтесь с демонстрационным кодом и примерами этих методов в примере stackblitz.