Listening to Angular Key Events with Host Listeners
A typical pattern in many web applications is the ability to react to users via keyboard events or shortcuts. This great for user experience and accessibility. Typically we register window and document events to accomplish this. With Angular, we try to avoid touching the DOM directly for certain rendering and performance reasons. There is a specific API within Angular we can use to listen to the global window and document events like the keyup
and keydown
events.
Host Listeners
To listen to the window
for events, we will use the HostListener
API. This API allows us to register a particular listener for events in the browser and then call methods in our components to react to them.
In our example, we have a simple counter component that can increment and decrement a value on the view. Our counter component will have two buttons. We will listen to the keyup
event to be able to use the keyboard arrow keys for the component. Here is our rendered output:
In our rendered counter component I can increment and decrement the value with the buttons and the keyboard arrow keys. Let's take a look at the component template first.
<h1>Angular Host Listeners and Key Events</h1>
<button (click)="decrement()">-</button>
{{value}}
<button (click)="increment()">+</button>
So in our template we show a single property value
and then have two buttons that call the increment()
and decrement()
methods. Take notice that all of the code to listen to key events will be on the TypeScript side of the component unlike the local click
events in the template.
import { Component, HostListener } from '@angular/core';
export enum KEY_CODE {
RIGHT_ARROW = 39,
LEFT_ARROW = 37
}
@Component({
selector: 'demo-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
value = 0;
constructor() {}
@HostListener('window:keyup', ['$event'])
keyEvent(event: KeyboardEvent) {
console.log(event);
if (event.keyCode === KEY_CODE.RIGHT_ARROW) {
this.increment();
}
if (event.keyCode === KEY_CODE.LEFT_ARROW) {
this.decrement();
}
}
increment() {
this.value++;
}
decrement() {
this.value--;
}
}
The first thing in our component is to notice the HostListener
decorator in import in out component. This special decorator is how we can listen to out host events. Out host is essentially the element or document our component is located in. We add the @HostListener
to the keyEvent()
method with a few important parameters.
@HostListener('window:keyup', ['$event'])
keyEvent(event: KeyboardEvent) {
console.log(event);
if (event.keyCode === KEY_CODE.RIGHT_ARROW) {
this.increment();
}
if (event.keyCode === KEY_CODE.LEFT_ARROW) {
this.decrement();
}
}
The @HostListener
has two parameters. The first is the name of the host event we would like to listen. For our use case, it will be the window:keyup
event. The second parameter takes a list of arguments returned by the event you are listening. So for our keyup
event Angular will pass us back a copy of the keyup
event via the $event
variable. This is similar to the $event
that we commonly use in our templates to pass back other local events.
Now the event is registered, every time the DOM triggers the event, Angular will call our keyEvent()
method passing in the event. Once we have the event, we can check the KeyboardEvent
for the key code. For our counter component, we created a simple TypeScript interface to hold the key codes we care about. When the appropriate key code is returned we call the increment()
or decrement()
methods.