Comment puis-je écouter l'événement de pression de touche sur toute la page?

109

Je cherche un moyen de lier une fonction à toute ma page (lorsqu'un utilisateur appuie sur une touche, je veux qu'il déclenche une fonction dans mon component.ts)

C'était facile dans AngularJS avec un ng-keypressmais ça ne marche pas avec (keypress)="handleInput($event)".

Je l'ai essayé avec un wrapper div sur toute la page mais cela ne semble pas fonctionner. cela ne fonctionne que lorsque l'accent est mis dessus.

<div (keypress)="handleInput($event)" tabindex="1">
L.querter
la source
Avez-vous essayé window:keypress?
KarolDepka

Réponses:

203

J'utiliser @HostListener décorateur au sein de votre composant:

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

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

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

Il existe également d'autres options comme:

propriété hôte au sein du @Componentdécorateur

Angular recommande d'utiliser le @HostListenerdécorateur sur la propriété hôte 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
la source
2
Ça marche bien. import {HostListener} de '@ angular / core' doit ajouter. et appelez même n'importe où dans le composant. Même le constructeur latéral fonctionne très bien
gnganpath
23
Merci pour cela, mais juste un avertissement pour les futurs lecteurs: si vous avez besoin des touches fléchées, utilisez la touche enfoncée au lieu d'appuyer sur une touche.
Troels Larsen
14
Si vous avez besoin de la escclé, utilisez keyupevent. Merci à @TroelsLarsen
Aron Lorincz
@yurzui, comment puis-je utiliser cet événement pour un composant particulier.pas sur toute la page
kamalav
1
@yurzui Comment puis-je détecter un function-key(F1, F2, F3, ...)?
Arpit Kumar
18

La réponse de yurzui n'a pas fonctionné pour moi, cela pourrait être une version RC différente, ou cela pourrait être une erreur de ma part. Quoi qu'il en soit, voici comment je l'ai fait avec mon composant dans Angular2 RC4 (qui est maintenant assez obsolète).

@Component({
    ...
    host: {
        '(document:keydown)': 'handleKeyboardEvents($event)'
    }
})
export class MyComponent {
    ...
    handleKeyboardEvents(event: KeyboardEvent) {
        this.key = event.which || event.keyCode;
    }
}
Adam
la source
3
C'est la même chose, juste une syntaxe alternative et vous avez utilisé à la keydownplace dekeypress
Günter Zöchbauer
Comme je l'ai dit, probablement une erreur de ma part, mais c'est ce qu'il a fallu pour que cela fonctionne pour moi. :)
Adam
Quel serait l'avantage de cela par rapport à l'utilisation de document.addEventListener? Est-ce juste un problème d'abstrait du DOM?
Ixonal
@Ixonal # 2 sur cet article décrit mieux que moi: angularjs.blogspot.ca/2016/04 / ... Fondamentalement, ce n'est pas la manière «angulaire», car elle est couplée avec le navigateur, et elle n'est pas testable. Peut-être pas un gros problème pour le moment, mais c'est un bon modèle à suivre.
Adam
1
Les derniers documents recommandent d'utiliser @HostListener: angular.io/docs/ts/latest/guide/…
saschwarz
11

Juste pour ajouter à cela en 2019 w Angular 8,

au lieu d'appuyer sur une touche, j'ai dû utiliser la touche enfoncée

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

à

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

Travailler Stacklitz

tshoemake
la source
Rapport angulaire 9: à la fois la pression de touche et la touche enfoncée enregistreraient les touches "asdf" normales, mais seule la touche enfoncée obtiendrait F4 et d'autres touches de fonction. Keypress pourrait obtenir des combinaisons de touches comme CTRL-Z, keydown les interprète séparément (une touche CTRL, puis quelques millisecondes plus tard, une touche Z).
Anders8
4

Si vous souhaitez exécuter un événement sur une pression de bouton du clavier spécifique, dans ce cas, vous pouvez utiliser @HostListener. Pour cela, vous devez importer HostListener dans votre fichier ts de composant.

import {HostListener} depuis '@ angular / core';
puis utilisez la fonction ci-dessous n'importe où dans votre fichier ts de composant.

@HostListener('document:keyup', ['$event'])
  handleDeleteKeyboardEvent(event: KeyboardEvent) {
    if(event.key === 'Delete')
    {
      // remove something...
    }
  }
Prabhat Maurya
la source
0

Je pense que cela fait le meilleur travail

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

par exemple dans app.component

constructor(private eventManager: EventManager) {
    const removeGlobalEventListener = this.eventManager.addGlobalEventListener(
      'document',
      'keypress',
      (ev) => {
        console.log('ev', ev);
      }
    );
  }
Whisher
la source