How can I listen for keypress event on the whole page?
Asked Answered
F

7

172

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">
Federate answered 21/5, 2016 at 11:45 Comment(1)
Have you tried window:keypress?Groveman
C
302

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();
  }
}
Cosmetician answered 21/5, 2016 at 12:59 Comment(11)
Werking fine. import {HostListener } from '@angular/core' have to add. and call even anywhere in component. Even out side contructor also working fineCreekmore
Thanks for this, but just a heads up for future readers: if you need the arrow keys, use keydown instead of keypress.Chessa
If you need the esc key, use keyup event. Thank to @TroelsLarsenMonah
@Cosmetician ,how can I use this event for particular component.not on whole pageNostoc
@Cosmetician How can I detect a function-key (F1, F2, F3, ...)?Gamine
@Cosmetician 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 ?Pyroelectric
@arpit-meena Use keydown (or keyup) instead of keypress to catch function keys. @HostListener('document:keydown', ['$event'])Oys
this won't detect 'escape'Bort
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.Russom
@Cosmetician 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.)Hannon
interestingly the new (angular 17) site mentions the opposite guide: Always prefer using the host property over HostBinding and HostListener. angular.dev/guide/components/…Foreside
B
27

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

Been answered 19/7, 2019 at 4:12 Comment(1)
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).Huan
N
22

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;
    }
}
Numskull answered 9/9, 2016 at 19:38 Comment(7)
That's the same, just alternative syntax and you used keydown instead of keypressBriard
Like I said, probably a mistake on my part, but that's what it took to get it to work for me. :)Numskull
What would be the benefit of this vs using document.addEventListener? Is it just an issue of abstracting away the DOM?Eltonelucidate
@Eltonelucidate #2 on this articles describes better than I can: angularjs.blogspot.ca/2016/04/… 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.Numskull
The latest docs recommend using @HostListener: angular.io/docs/ts/latest/guide/…Fourwheeler
doesnt work!property 'key' does not exists in the current context.Fescue
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.Numskull
K
7

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...
    }
  }
Katykatya answered 9/5, 2018 at 12:48 Comment(0)
R
2

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

Link: https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event

Roup answered 27/7, 2020 at 13:33 Comment(0)
R
2

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);
      }
    );
  }
Ruthieruthless answered 28/7, 2020 at 20:17 Comment(1)
addGlobalEventListener is @deprecated — No longer being used in Ivy code. To be removed in version 14.Amy
C
2

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;
    }
}
Cahn answered 20/9, 2022 at 11:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.