Angular 2+ элегантный способ перехвата Command+S

Пытаюсь реализовать сочетание клавиш Command+S для сохранения формы.

Я прочитал это — https://angular.io/guide/user-input, но он ничего не говорит о мета или команде.

Пробовал окружать форму с помощью:

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

Из них работали только control.u и control.s.

Со всей мощью и кросс-браузерными возможностями Angular 2+ я надеялся, что с этим как-то элегантно справятся, используя (keyup...).

И наверняка многие разработчики Angular используют Mac :).

Я также прочитал Как можно захватить команду Mac key через JavaScript? и http://unixpapa.com/js/key.html но все еще надеюсь на элегантное решение Angular вместо того, чтобы бороться со специфическими для браузера вещами...


person KarolDepka    schedule 08.08.2017    source источник


Ответы (3)


ОБНОВЛЕНИЕ

Чтобы диалог сохранения браузера не открывался, мы должны использовать событие keydown вместо keyup и вызвать функцию $event.preventDefault();. Обновленный код ниже:

  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();
    } 
  }

Затем привяжите этот метод к событию (keydown) в вашем div:

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

Обновлен ДЕМО-ПРОГРАММА PLUNKER


ИСХОДНЫЙ ОТВЕТ

Вот идея, как насчет обнаружения события в вашем классе:

  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();
    } 
  }

Затем привяжите этот метод к событию (keyup) в вашем div:

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

Вот ссылка на плункер: ДЕМО-ПЛАНКЕР

person Faisal    schedule 08.08.2017
comment
Для мета-ключей есть логическое значение, которое является клавишей Command на Mac, это event.metaKey. - person Adam LeBlanc; 08.08.2017
comment
@KarolDepka в Mac у вас есть metaKey. Смотрите обновленный ответ. - person Faisal; 08.08.2017
comment
Пробовал $event.metaKey. Странно ведет себя. Мне еще не удалось зафиксировать какую-либо полезную комбинацию клавиш с metaKey... Как будто это не клавиша-модификатор (о которой я тоже где-то читал...) - person KarolDepka; 08.08.2017
comment
@AdamLeBlanc: вам удалось зафиксировать фактические комбинации клавиш мета+буква, используя metaKey? - person KarolDepka; 08.08.2017
comment
вот полезная статья о комбинациях клавиш: bennadel.com/blog/ - person Faisal; 08.08.2017
comment
@Faisal: для меня ваш обновленный пример (с $event.metaKey) не работает ни в Chrome, ни в Firefox, ни в Safari. Для Cmd + S открывается диалоговое окно «Сохранить веб-страницу». Вы пытались его запустить? - person KarolDepka; 08.08.2017
comment
div по умолчанию не фокусируется. Я тестирую элемент ввода. Я создал планк для этого, вот ссылка: plnkr.co/edit/xtaTjKzPwIDXpc77ZcUj?p =preview [Я пытаюсь понять, как остановить открытие диалогового окна сохранения] - person Faisal; 08.08.2017
comment
@Faisal: пока единственное, что смогло захватить команды + (клавиша ВНИЗ) - bennadel.github.io/JavaScript-Demos/demos/ — источник github.com/bennadel/JavaScript-Demos/blob/master/demos/ - person KarolDepka; 08.08.2017
comment
@Faisal: для предотвращения диалога сохранения, может быть: $event.preventDefault(); - person KarolDepka; 08.08.2017
comment
@Faisal - интересно, для меня ваш Plunkr, похоже, не обнаруживает Cmd + S ... Вы на Mac? - person KarolDepka; 08.08.2017
comment
я на окнах - person Faisal; 08.08.2017
comment
@KarolDepka Я обновил плункер для обнаружения платформы - person Faisal; 08.08.2017
comment
@Faisal Я принял этот ответ, хотя остается вопрос, как избавиться от диалогового окна сохранения страницы в браузере, перехватывающего сочетание клавиш, которое мы надеемся решить в ближайшее время ;-). - person KarolDepka; 10.08.2017
comment
Для глобальных ярлыков можно использовать префикс window:, например: <div (window:keydown.meta.s)="keyDownSave($event)" (window:keydown.control.s)="keyDownSave($event)" > - person KarolDepka; 11.08.2017

Глобальный слушатель, не устаревший ответ:

@HostListener('window:keydown', ['$event'])
onKeyDown(event: KeyboardEvent) {
    if ((event.metaKey || event.ctrlKey) && event.key === 's') {
        this.save();
        event.preventDefault();
    }
}
person Chris Fremgen    schedule 07.09.2020

  1. Методы preventDefault() и stopPropagation() и т. д. у меня не работали (используя текущий Chrome), поэтому мне пришлось использовать несколько клавиш: ctrl+shift+s
  2. При определении обработчика событий в моем компоненте он работал только для этого дочернего сайта и только в том случае, если некоторые входные данные формы были в фокусе, поэтому мне пришлось добавить прослушиватель в другом месте.
  3. Я сжал несколько функций, так как мне все равно, в какой среде вызывается горячая клавиша, я хочу сохранить свой объект.
ngOnInit() {   
  document.body.addEventListener("keydown", event => {
    let charCode = String.fromCharCode(event.which).toLowerCase();
    switch (((navigator.platform.match('Mac') && event.metaKey) || event.ctrlKey) && event.shiftKey && charCode === 's') {
      case true: {
        this.saveArticle(); //whatever your usecase is
        break;
      }
    }
  });
}
person connectedMind    schedule 03.11.2020