Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2+ elegant way to intercept Command+S

Trying to implement a shortcut key combination for Command+S to save a form.

I've read this - https://angular.io/guide/user-input, but it does not say anything about meta or command.

Tried surrounding the form with:

<div
  (keyup.command.s)="save()"
  (keyup.command.u)="save()"
  (keyup.control.u)="save()"
  (keyup.control.s)="save()"
  (keyup.meta.u)="save()"
>

Of those, only control.u and control.s worked.

With all the power and cross-browser capabilities of Angular 2+, I was hoping that this is somehow handled in an elegant way, using (keyup...).

And for sure many Angular Devs use Macs :).

I've also read How does one capture a Mac's command key via JavaScript? and http://unixpapa.com/js/key.html but still hoping for Angular elegant solution instead of fighting with browser-specific stuff...

like image 727
KarolDepka Avatar asked Aug 08 '17 12:08

KarolDepka


2 Answers

Global listener, non-deprecated answer:

@HostListener('window:keydown', ['$event'])
onKeyDown(event: KeyboardEvent) {
    if ((event.metaKey || event.ctrlKey) && event.key === 's') {
        this.save();
        event.preventDefault();
    }
}
like image 121
Chris Fremgen Avatar answered Nov 18 '22 19:11

Chris Fremgen


UPDATE

To stop the save dialog of the browser from opening, we must use the keydown event instead of keyup and call the function $event.preventDefault();. Updated code below:

  onKeyDown($event): void {
    // Detect platform
    if(navigator.platform.match('Mac')){
        this.handleMacKeyEvents($event);
    }
    else {
        this.handleWindowsKeyEvents($event); 
    }
  }

  handleMacKeyEvents($event) {
    // MetaKey documentation
    // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
    let charCode = String.fromCharCode($event.which).toLowerCase();
    if ($event.metaKey && charCode === 's') {
        // Action on Cmd + S
        $event.preventDefault();
    } 
  }

  handleWindowsKeyEvents($event) {
    let charCode = String.fromCharCode($event.which).toLowerCase();
    if ($event.ctrlKey && charCode === 's') {
        // Action on Ctrl + S
        $event.preventDefault();
    } 
  }

Then bind this method to the (keydown) event in your div:

<div (keydown)="onKeyDown($event)" tabindex="0">
</div>

Updated PLUNKER DEMO


ORIGINAL ANSWER

Here is an idea, how about detecting the event in you class:

  onKeyUp($event): void {
    // Detect platform
    if(navigator.platform.match('Mac')){
        this.handleMacKeyEvents($event);
    }
    else {
        this.handleWindowsKeyEvents($event); 
    }
  }

  handleMacKeyEvents($event) {
    // MetaKey documentation
    // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
    let charCode = String.fromCharCode($event.which).toLowerCase();
    if ($event.metaKey && charCode === 's') {
        // Action on Cmd + S
        $event.preventDefault();
    } 
  }

  handleWindowsKeyEvents($event) {
    let charCode = String.fromCharCode($event.which).toLowerCase();
    if ($event.ctrlKey && charCode === 's') {
        // Action on Ctrl + S
        $event.preventDefault();
    } 
  }

Then bind this method to the (keyup) event in your div:

<div (keyup)="onKeyUp($event)" tabindex="0">
</div>

Here is a plunker link: PLUNKER DEMO

like image 8
Faisal Avatar answered Nov 18 '22 19:11

Faisal