Como posso ouvir o evento de pressionamento de tecla em toda a página?

109

Estou procurando uma maneira de vincular uma função a minha página inteira (quando um usuário pressiona uma tecla, quero que ela acione uma função em meu component.ts)

Foi fácil no AngularJS com um, ng-keypressmas não funciona (keypress)="handleInput($event)".

Eu tentei com um invólucro div em toda a página, mas não parece funcionar. só funciona quando o foco está nele.

<div (keypress)="handleInput($event)" tabindex="1">
L.querter
fonte
Você já tentou window:keypress?
KarolDepka

Respostas:

203

Eu usaria o decorador @HostListener em seu componente:

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

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

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

Existem também outras opções como:

propriedade hospedeira dentro do @Componentdecorador

A Angular recomenda o uso de @HostListenerdecorador em vez de propriedade host 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
fonte
2
Tudo bem. import {HostListener} de '@ angular / core' tem que adicionar. e ligue até mesmo em qualquer parte do componente. Mesmo o
contrutor externo
23
Obrigado por isso, mas apenas um aviso para futuros leitores: se você precisar das teclas de seta, use a tecla pressionada em vez de pressionar a tecla.
Troels Larsen
14
Se você precisar da escchave, use o keyupevento. Obrigado a @TroelsLarsen
Aron Lorincz
@yurzui, como posso usar este evento para um determinado componente. não na página inteira
kamalav
1
@yurzui Como posso detectar um function-key(F1, F2, F3, ...)?
Arpit Kumar
18

A resposta de yurzui não funcionou para mim, pode ser uma versão RC diferente ou pode ser um erro da minha parte. De qualquer forma, aqui está como eu fiz com meu componente no Angular2 RC4 (que agora está bastante desatualizado).

@Component({
    ...
    host: {
        '(document:keydown)': 'handleKeyboardEvents($event)'
    }
})
export class MyComponent {
    ...
    handleKeyboardEvents(event: KeyboardEvent) {
        this.key = event.which || event.keyCode;
    }
}
Adão
fonte
3
Essa é a mesma, apenas sintaxe alternativa e você usou em keydownvez dekeypress
Günter Zöchbauer
Como eu disse, provavelmente um erro da minha parte, mas foi o que foi preciso para fazer funcionar para mim. :)
Adam,
Qual seria a vantagem disso em comparação com o uso de document.addEventListener? É apenas uma questão de abstrair o DOM?
Ixonal
@Ixonal # 2 neste artigo descreve melhor do que eu: angularjs.blogspot.ca/2016/04/… Basicamente, não é o caminho 'Angular', porque está acoplado ao navegador e não pode ser testado. Talvez não seja grande coisa agora, mas é um bom modelo a seguir.
Adam,
1
Os documentos mais recentes recomendam o uso de @HostListener: angular.io/docs/ts/latest/guide/…
saschwarz
11

Só para adicionar a isso em 2019 w Angular 8,

em vez de pressionar a tecla, tive que usar keydown

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

para

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

Stacklitz de trabalho

tshoemake
fonte
Relatório Angular 9: tanto o keypress quanto o keydown registrariam as teclas "asdf" normais, mas apenas o keydown obteria F4 e outras teclas de função. Keypress pode obter alguns combos de teclas como CTRL-Z, keydown os interpreta separadamente (uma tecla CTRL e, milissegundos depois, uma tecla Z).
Anders8
4

Se você quiser realizar qualquer evento em qualquer pressionamento de botão específico do teclado, nesse caso, você pode usar @HostListener. Para isso, você deve importar HostListener no arquivo ts do seu componente.

import {HostListener} de '@ angular / core';
em seguida, use a função abaixo em qualquer lugar no arquivo ts do seu componente.

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

Eu acho que isso faz o melhor trabalho

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

por exemplo em app.component

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