0

What approach would you recommend to control the whole app with keyboard only? I found Spotlight lib, but it depends on enyojs which seems to have its own component model and overall enyojs seems to be an overkill.

So far I'm listening on keydown events in app.component.ts:

@HostListener('window:keydown', ['$event']) onKeydown(event: any) {
  event.preventDefault();
  this.mainKeydownHandler.handle(event.keyCode);
}

Each component which want to handle keydown events registers to MainKeydownHandler's handlers and when keydown event occures MainKeydownHandler delegates an event to the registered handler. The appropriate handler is determined by document.activeElement's class (I did not find more "angular2-like" way to get currently focused elem) in MainKeydownHandler's handle method. So now I have to add appropriate class name to a group of elements I want to be able to focus.

Furthermore, component's handler gets all selectable elements with:

@ViewChildren('selectable') elements: QueryList<ElementRef>;

so I need to add #selectable and class with ID of handler to each element I want to focus. Component's handler then receives keyCode and determines which element to select next, or return to previouslly selected elem from another component and so on.

This approach seems awkward, involves quite a lot of code when new component want to handle keydown events and there are situations when a component completely loses focus: when I delete an item from some list and then this component is rerendered (some service or MainKeydownHandler could remember, but this could lead to quite a lot of elements to remember along the way navigating user through components).

Is there a better, simpler, more generic and more declarative way to control entire angular2 app with keyboard-only (keydown/keyup events)?

Alternatively, is it reasonable to use Spotlight (with enyojs dep.) with angular2 for this use-case? And can you provide working plunker with angular2+spotlight. I could not get these two to work together.

Petr Marek
  • 1,381
  • 1
  • 15
  • 31

2 Answers2

1

If you want to enable basic keyboard navigation, you can do it with tabindex which is a standard way of doing it. See the specification

document.getElementById('mylist').focus();
:focus{
  border: 1px solid red;
  }
Press TAB to navigate.
<ul id="mylist" tabindex="-1">
    <li tabindex="1"> One </li>
    <li tabindex="2"> Two </li>
    <li tabindex="4"> Four </li>
    <li tabindex="3"> Three </li>
</ul>

If you want to do it with arrow keys, you will have to listen to keydown event on the document and manually focus() the elements using javascript. It will be easier to navigate back and forth, not that direct to find the element that is above and below current element in layout. You will have to compare x,y coordinates or offsets.

document.getElementById('mylist').focus();

window.onkeydown = function(e) {
  var curr = document.activeElement;
  var treeWalker = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_ELEMENT,
    { acceptNode: function(node) { return (node.tabIndex === -1)?NodeFilter.FILTER_SKIP: NodeFilter.FILTER_ACCEPT} },
    false
);
  treeWalker.currentNode = curr;
  
  if (e.keyCode == 39) {
     treeWalker.nextNode().focus();
  }
  if (e.keyCode == 37) {
     treeWalker.previousNode().focus();
  }
};
:focus {
  border: 1px solid red;
}
Press Right/Left arrow keys to navigate
<ul id="mylist" tabindex="-1">
  <li tabindex="1">One</li>
  <li tabindex="2">Two</li>
  <li tabindex="4">Four</li>
  <li tabindex="3">Three</li>
  <li>Not selectable</li>
  <li tabindex="5">Five</li>
</ul>
sabithpocker
  • 15,274
  • 1
  • 42
  • 75
1

You can take a look at https://github.com/luke-chang/js-spatial-navigation It's a generic spatial navigation library. It should be able to be integrated easily with Angular.

You may also want to check out this related SO: Navigate the UI using only keyboard

And this Angular TV app which purports to have spatial navigation: https://github.com/ahmednuaman/angular-tv-app

Community
  • 1
  • 1
Pre101
  • 2,370
  • 16
  • 23
  • I was trying to create a TV app using angular 4 but unable to use `js-spacial-navigation`. any thoughts on how to use it? – Santosh Mar 05 '18 at 07:09
  • I don't know! We (LG) created a fork of the library for use with our Enact framework. It's called Spotlight and is available on npm here: https://www.npmjs.com/package/@enact/spotlight However, it's primarily for use with React. – Pre101 May 10 '18 at 17:26