25

I am trying to trace when a user presses a Shift+Tab combination key using keyboard, but I am not able to fire that event

@HostListener('keyup', ['$event'])
@HostListener('keydown', ['$event'])

onkeyup(event) {
  if (event.keyCode == 16 && event.keyCode == 9) {
    this.isShift = true;
    console.log("On Keyup " + event.keyCode);
  }
}

onkeydown(event) {
  console.log("On KeyDown" + event.keyCode);
}
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Mithun Sudheendran
  • 271
  • 1
  • 3
  • 6
  • 1
    your post here actually became an answer to my question... how to listen to either mouse event or keyboard event. And the solution is by stacking HostListener Annotations on a function. – Artanis Zeratul Jul 09 '19 at 01:54

2 Answers2

31

Although the solution by Frank Modica works, using Angular's key event filtering and pseudo-events would be a more readable and cleaner solution:

@Directive({
    selector: '[keyHandler]'
})
export class KeyHandlerDirective {

    @HostListener('keydown.shift.tab', ['$event'])
    onKeyDown(e) {
        // optionally use preventDefault() if your combination
        // triggers other events (moving focus in case of Shift+Tab)
        // e.preventDefault();
        console.log('shift and tab');
    }
}

// in template:
<input type="text" keyHandler />

More examples of how pseudo-events work can be found here.

Aziz Yokubjonov
  • 656
  • 6
  • 9
  • 3
    Angular's documentation is awful on this but this article helped me: https://medium.com/claritydesignsystem/angular-pseudo-events-d4e7f89247ee – azulBonnet Jul 30 '19 at 20:07
  • @MithunSudheendran Maybe you want to mark this solution as the accepted answer? It is cleaner than mine :) – Frank Modica Nov 17 '21 at 14:31
19

It works when I do this:

@Directive({
  selector: '[test-directive]'
})
export class TestDirective {
  @HostListener('keydown', ['$event']) onKeyDown(e) {
    if (e.shiftKey && e.keyCode == 9) {
      console.log('shift and tab');
    }
  }
}

<input type="text" test-directive />

Note that keyup can be tricky because tab may unfocus the element. So by the time keyup fires, you may be on the next element, so keyup may actually fire on that element. So it depends on what you need. But keydown works for the current element.

Frank Modica
  • 10,238
  • 3
  • 23
  • 39
  • Is it possible to use test-directive inside a Component? Eg: I have component, i want to track the Shift+Tab Event inside this component – Mithun Sudheendran Jun 06 '17 at 04:46
  • Yes, it will work if you put `test-directive` on an element that contains other elements which can fire `keydown` events, because the events bubble. Note that non-input elements like plain `div` elements may not fire `keydown` events unless you add `tabindex`. Check out this link: https://stackoverflow.com/questions/3149362/capture-key-press-or-keydown-event-on-div-element – Frank Modica Jun 06 '17 at 14:59
  • @FrankModica, how about if I want to capture either mouse event or keyboard event? Thanks. – Artanis Zeratul Jul 09 '19 at 01:42
  • @ArtanisZeratul I'm sorry I haven't worked with this in a while. Maybe you need more HostListeners. – Frank Modica Jul 09 '19 at 22:20