Cory Rylan

My name is , Google Developer Expert, Speaker, Software Developer. Building Design Systems and Web Components.

Follow @coryrylan
Angular

Listening to Angular Key Events with Host Listeners

Cory Rylan

- 3 minutes

Updated

This article has been updated to the latest version Angular 17 and tested with Angular 16. The content is likely still applicable for all Angular 2 + versions.

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.

View Demo Code   
Twitter Facebook LinkedIn Email
 

No spam. Short occasional updates on Web Development articles, videos, and new courses in your inbox.

Related Posts

Angular

Creating Dynamic Tables in Angular

Learn how to easily create HTML tables in Angular from dynamic data sources.

Read Article
Web Components

Reusable Component Patterns - Default Slots

Learn about how to use default slots in Web Components for a more flexible API design.

Read Article
Web Components

Reusable Component Anti-Patterns - Semantic Obfuscation

Learn about UI Component API design and one of the common anti-patterns, Semantic Obfuscation.

Read Article