Keyboard shortcuts are integral part of any application. It provides an alternative way of doing something which you typically do using a mouse. Many applications rely heavily on keyboard short cuts as it increases productivity and once users are used to it they would hardly use mouse to perform that task again!
When working with Angular you can use inbuilt features like “HostListeners” for basic keyboard handling but when it comes to advanced keyboard shortcut handling it becomes complicated to use native HostListeners.
A quick search will take you to one of the most popular keyboard handling library Mousetrap. Mousetrap is an extremely capable library, in addition to handling normal keyboard combinations it can also handle key sequences like gmail. You can also bind multiple keyboard shortcuts for a single task. But using it in angular a little bit tricky as you have to bind call back functions and remember to bind and unbind these keys with angular component life cycle, also it doesn’t gel well with conventions of Angular and RxJS.
Using Mousetrap in Angular
Let’s say you have a full page configuration form with a save button at the bottom and you want user to press cmd+s or ctrl+s anywhere on the page and trigger the save. Using plain vanilla mousetrap you will have to do something like
This is very imperative! In the world of declarative Angular templates you still have to bind callbacks to track each keyboard shortcut pressed. So I decided to write a wrapper over mousetrap using Angular ngx-mousetrap.
I started the ngx-mousetrap by writing an Angular service which does most of the heavy lifting. The service takes care of binding the callbacks with mousetrap and returning an observable back for each keyboard shortcut registered. It also takes care of binding mousetrap callbacks against a scope if required. If a keyboard shortcut is already bound then it simply returns the previous observable rather than registering double callbacks.
This service can be injected into the component and gels well with the angular structure of using observables.
Though this is somewhat similar to using mousetrap as it is, it has added advantage of using RxJS, but we will have to deal with registering and unregistering the keyboard shortcuts on component creation and destroy. A directive which further abstracts it out will be much cleaner approach.
A directive can hide the complexity and bind the registering and unregistering keyboard shortcuts with component lifecycle. It can registers the shortcuts when component is created and unregister when it is destroyed.
The directive not only has “mousetrapKeyPressed” event emitter it also simulates a mouse-click on the object which will end up calling “(click)” event binding. So you don’t need have add any additional event handler for keyboard shortcut if the target supports a click event. If you don’t want the “click” event to trigger you can use “suppressAutoClick” Input.
Now this directive can simply be used in the Angular html template declaratively as below
That is all what is needed now to register a keyboard shortcut for a button. This is much more declarative and we no longer need any typescript code.
The source for the library and example application can be found at https://github.com/nagarsuresh/ngx-mousetrap-angular.
The demo is available at https://nagarsuresh.github.io/ngx-mousetrap-angular/
The library is also published in npm at https://www.npmjs.com/package/ngx-mousetrap