163

I'm looking for a way to bind a function to my whole page (when a user presses a key, I want it to trigger a function in my component.ts)

It was easy in AngularJS with a ng-keypress but it does not work with (keypress)="handleInput($event)".

I tried it with a div wrapper on the whole page but it doesn't seem to work. it only works when the focus is on it.

<div (keypress)="handleInput($event)" tabindex="1">
Dale K
  • 25,246
  • 15
  • 42
  • 71
L.querter
  • 2,332
  • 2
  • 13
  • 23

7 Answers7

288

I would use @HostListener decorator within your component:

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

@Component({
  ...
})
export class AppComponent {

  @HostListener('document:keypress', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) { 
    this.key = event.key;
  }
}

There are also other options like:

host property within @Component decorator

Angular recommends using @HostListener decorator over host property https://angular.io/guide/styleguide#style-06-03

@Component({
  ...
  host: {
    '(document:keypress)': 'handleKeyboardEvent($event)'
  }
})
export class AppComponent {
  handleKeyboardEvent(event: KeyboardEvent) {
    console.log(event);
  }
}

renderer.listen

import { Component, Renderer2 } from '@angular/core';

@Component({
  ...
})
export class AppComponent {
  globalListenFunc: Function;

  constructor(private renderer: Renderer2) {}

  ngOnInit() {
    this.globalListenFunc = this.renderer.listen('document', 'keypress', e => {
      console.log(e);
    });
  }

  ngOnDestroy() {
    // remove listener
    this.globalListenFunc();
  }
}

Observable.fromEvent

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import { Subscription } from 'rxjs/Subscription';

@Component({
  ...
})
export class AppComponent {
  subscription: Subscription;

  ngOnInit() {
    this.subscription = Observable.fromEvent(document, 'keypress').subscribe(e => {
      console.log(e);
    })
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
yurzui
  • 205,937
  • 32
  • 433
  • 399
  • 2
    Werking fine. import {HostListener } from '@angular/core' have to add. and call even anywhere in component. Even out side contructor also working fine – gnganapath Apr 25 '17 at 09:53
  • 33
    Thanks for this, but just a heads up for future readers: if you need the arrow keys, use keydown instead of keypress. – Troels Larsen May 28 '17 at 20:45
  • 19
    If you need the `esc` key, use `keyup` event. Thank to @TroelsLarsen – Aron Lorincz Aug 10 '17 at 10:19
  • @yurzui ,how can I use this event for particular component.not on whole page – kamalav Dec 04 '17 at 05:50
  • 2
    @yurzui How can I detect a `function-key` (F1, F2, F3, ...)? – Arpit Kumar Dec 18 '17 at 06:38
  • @yurzui i wanted to ask one thing on this, this actually will trigger for the whole document what if i have multiple small components in the view and one is in focus i only want to trigger or listen to the click or mouse events for that component and all other components too have this but are not in focus ? – Rahul Singh Jan 13 '18 at 20:33
  • @arpit-meena Use keydown (or keyup) instead of keypress to catch function keys. `@HostListener('document:keydown', ['$event'])` – bts Mar 21 '18 at 17:06
  • this won't detect 'escape' – Steinfeld Feb 20 '19 at 23:11
  • Can someone explain why doing this in a directive does not work? Such as in the directive having the selector choose the `app-root` element. This does not seem to fire any keypress events. – thienedits Jun 25 '20 at 08:20
  • @yurzui You can detect Function Keys by using the `keydown`/`keyup` events and then be sure to call `event.preventDefault()` on the event to prevent it being handled by your browser. (For instance if you don't stop it from bubbling up, your browser will open a help screen when you press `F1`.) – tpartee Jul 07 '20 at 20:40
25

Just to add to this in 2019 w Angular 8,

instead of keypress I had to use keydown

@HostListener('document:keypress', ['$event'])

to

@HostListener('document:keydown', ['$event'])

Working Stacklitz

dota2pro
  • 7,220
  • 7
  • 44
  • 79
tshoemake
  • 1,311
  • 1
  • 17
  • 28
  • Angular 9 report: both keypress and keydown would register normal "asdf" keys, but only keydown would get F4 and other function keys. Keypress could get some key combos like CTRL-Z, keydown interprets those separately (a CTRL key, then milliseconds later, a Z key). – MotoRidingMelon Jun 01 '20 at 11:23
21

yurzui's answer didn't work for me, it might be a different RC version, or it might be a mistake on my part. Either way, here's how I did it with my component in Angular2 RC4 (which is now quite outdated).

@Component({
    ...
    host: {
        '(document:keydown)': 'handleKeyboardEvents($event)'
    }
})
export class MyComponent {
    ...
    handleKeyboardEvents(event: KeyboardEvent) {
        this.key = event.which || event.keyCode;
    }
}
Adam
  • 4,445
  • 1
  • 31
  • 49
  • 3
    That's the same, just alternative syntax and you used `keydown` instead of `keypress` – Günter Zöchbauer Sep 09 '16 at 19:42
  • Like I said, probably a mistake on my part, but that's what it took to get it to work for me. :) – Adam Sep 09 '16 at 20:55
  • What would be the benefit of this vs using document.addEventListener? Is it just an issue of abstracting away the DOM? – Ixonal Oct 03 '16 at 17:46
  • @Ixonal #2 on this articles describes better than I can: http://angularjs.blogspot.ca/2016/04/5-rookie-mistakes-to-avoid-with-angular.html Basically, it's not the 'Angular' way, because it's coupled with the browser, and it's not testable. Maybe not a big deal right now, but it's a good model to follow. – Adam Oct 03 '16 at 19:53
  • 1
    The latest docs recommend using @HostListener: https://angular.io/docs/ts/latest/guide/style-guide.html#!#-a-id-06-03-a-use-hostlistener-and-hostbinding-class-decorators – saschwarz Oct 14 '16 at 21:44
  • doesnt work!property 'key' does not exists in the current context. –  Jul 04 '17 at 06:30
  • You can't just copy-paste code and expect it to work without modifications @ritesh. You need to either define `key` as a class variable, or change the assignment to assign to a local variable. – Adam Jul 04 '17 at 19:15
6

If you want to perform any event on any specific keyboard button press, in that case, you can use @HostListener. For this, you have to import HostListener in your component ts file.

import { HostListener } from '@angular/core';
then use below function anywhere in your component ts file.

@HostListener('document:keyup', ['$event'])
  handleDeleteKeyboardEvent(event: KeyboardEvent) {
    if(event.key === 'Delete')
    {
      // remove something...
    }
  }
Prabhat Maurya
  • 1,058
  • 16
  • 21
1

Be aware "document:keypress" is deprecated. We should use document:keydown instead.

Link: https://developer.mozilla.org/fr/docs/Web/API/Document/keypress_event

1

I think this does the best job

https://angular.io/api/platform-browser/EventManager

for instance in app.component

constructor(private eventManager: EventManager) {
    const removeGlobalEventListener = this.eventManager.addGlobalEventListener(
      'document',
      'keypress',
      (ev) => {
        console.log('ev', ev);
      }
    );
  }
Whisher
  • 31,320
  • 32
  • 120
  • 201
1

I struggeled a little bit on this one so; tshoemake provided the correct answer that also works for F keys. To prevent the F key from executing it's original browser action, like search, also call the preventDefault() method.

add the following includes

import { Component, HostListener } from '@angular/core';

and

@HostListener('document:keydown', ['$event'])
handleTheKeyboardEvent(event: KeyboardEvent) {
    switch (event.key) {
      case "F2":
        this.myF2Action();
        event.preventDefault();
        break;
    }
}
kjz99
  • 61
  • 4