23

Trying to monitor keyboard events with Angular 2 using TypeScript and What is Angular2 way of creating global keyboard shortcuts (a.k.a. hotkeys)? was helpful but tslint (codelyzer) objects with the message

In the "@Component" class decorator you are using the "host" property, this is considered bad practice. Use "@HostBindings", "@HostListeners" property decorator instead.

How do I use the recommended decorators? I'm not sure how the examples in Angular 2: Host binding and Host listening apply to my use case as I am not binding to any DOM elements.

Here is my demo

@Component({
  selector: 'my-app',
 template: `
    <div>
      <h2>Keyboard Event demo</h2>
      Start typing to see KeyboardEvent values
    </div>
    <hr />
    KeyboardEvent
    <ul>
      <li>altKey: {{altKey}}</li>
      <li>charCode: {{charCode}}</li>
      <li>code: {{code}}</li>
      <li>ctrlKey: {{ctrlKey}}</li>
      <li>keyCode: {{keyCode}}</li>
      <li>keyIdentifier: {{keyIdentifier}}</li>
      <li>metaKey: {{metaKey}}</li>
      <li>shiftKey: {{shiftKey}}</li>
      <li>timeStamp: {{timeStamp}}</li>
      <li>type: {{type}}</li>
      <li>which: {{which}}</li>
    </ul>
      `,
  host: { '(window:keydown)': 'keyboardInput($event)' }
  /*
  In the "@Component" class decorator you are using the "host" property, this is considered bad practice. 
  Use "@HostBindings", "@HostListeners" property decorator instead.
  */

})
export class App {

  /* a few examples */
  keyboardEvent: any;
  altKey: boolean;
  charCode: number;
  code: string;
  ctrlKey: boolean;
  keyCode: number;
  keyIdentifier: string;
  metaKey: boolean;
  shiftKey: boolean;
  timeStamp: number;
  type: string;
  which: number;

  keyboardInput(event: any) {
    event.preventDefault();
    event.stopPropagation();

    this.keyboardEvent = event;
    this.altKey = event.altKey;
    this.charCode = event.charCode;
    this.code = event.code;
    this.ctrlKey = event.ctrlKey;
    this.keyCode = event.keyCode;
    this.keyIdentifier = event.keyIdentifier;
    this.metaKey = event.metaKey;
    this.shiftKey = event.shiftKey;
    this.timeStamp = event.timeStamp;
    this.type = event.type;
    this.which = event.which;
  }

}

https://plnkr.co/edit/Aubybjbkp7p8FPxqM0zx

3
  • FYI -- the plunker referenced above isn't working for me in IE 11, but it works nicely in Chrome. It gets stuck at Loading... Commented Aug 18, 2016 at 14:52
  • host: { '(window:keydown)': 'keyboardInput($event)' } and keyboardInput(event: any) {} is the answer, thanx !!! Commented Jul 6, 2017 at 15:08
  • you can try ngxyz-konami Commented Dec 12, 2019 at 21:35

2 Answers 2

35
import {HostListener} from '@angular/core';

@HostListener('window:keydown', ['$event'])
handleKeyDown(event: KeyboardEvent) {
  // event.key === 'ArrowUp'
}
  • @HostBindings('attr.foo') foo = 'bar' is to bind values from your component instance to the host element like class, attributes, properties or styles.
Sign up to request clarification or add additional context in comments.

6 Comments

I have seen it mentioned in comments that using host: {} is discouraged and @HostBinding(), @HostListener() are preferred, but I haven't seen this mentioned from the Angular team.
How do I do the same for esc key?
There is no difference. Add if (event.keyCode == 27) { ... } to check if the event is the esc key.
@GünterZöchbauer They did, check it out here
While @HostListener works great, it also makes (my) Angular change detection run for the parent component on each key press. Using Observable.fromEvent(window, 'keydown').subscribe(...) does not. I guess one could create a decorator to run the decorated method outside of Angular's zone, but I've not tried.
|
1

Template (.html)

<div (keydown)="keyPressed($event)">...</div>

Class (.ts)

  keyPressed(keyEvent: KeyboardEvent): void {
    if (keyEvent.key === 'ArrowLeft') {
      console.log('LEFT');
    }
    else if (keyEvent.key === 'ArrowRight') {
      console.log('RIGHT');
    }
  }

The element where you put the event listener or any of its children must be focused to work. For capturing globally use <div (window:keydown)...>.

I think this is a more Angular way™ alternative. From the docs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.