By

(AngularJS, JQuery) Enterキーでフォーカスを遷移させるディレクティブを作る

ビジネスバンクグループ エンジニア の高橋 慶太です。

今回は、Enterキーでフォーカスを遷移させるAngularJSのディレクティブの作り方について書きたいと思います。

コード

早速ですが、コードはこんな感じになります。

  // HTML
  <body ng-app="app">
  ・・・
  <input type="text" name="sample_text1" tabindex="1" move-focus-by-enter-key/>
  <input type="text" name="sample_text2" tabindex="2" move-focus-by-enter-key/>
  ・・・
  </body>
  // AngularJSのDirective
  var app = angular.module("app", []);
  app.directive("moveFocusByEnterKey", function() {
      return function(scope, element, attrs) {
          element.bind("keydown keypress", function (event) {
              var destinationTabIndex = null;
              var destinationListIndex = null;
              var targetElementsCondition = 'textarea:enabled:visible,' +
                  'input:enabled:visible:not([readonly]),' + 
                  'select:enabled:visible,' +
                  'button:enabled:visible';
              var keyCode = event.which || event.keyCode;

              if (keyCode === 13 && !event.shiftKey && !event.altKey) {
                  var $list = $(targetElementsCondition);
                  $list.each(function(index) {
                      if (this.tabIndex &&
                          this.tabIndex >= 0 &&
                          this.tabIndex > event.target.tabIndex &&
                          (!destinationTabIndex || destinationTabIndex > this.tabIndex)) {
                          destinationTabIndex = this.tabIndex;
                          destinationListIndex = index;
                      }
                  });
                  if (destinationListIndex) {
                      $list.eq(destinationListIndex).focus();
                      event.preventDefault();
                  }
              }
          });
      };
  });

コード解説

JQueryのセレクタを使って対象のタグを絞り込む

HTMLタグには、input、div、select・・・などなど色々なものがあるので、
まずはその中でも「フォーカス遷移可能」なものを検索します!

  // 検索条件
  var targetElementsCondition = 'textarea:enabled:visible,' +
      'input:enabled:visible:not([readonly]),' + 
      'select:enabled:visible,' +
      'button:enabled:visible';
  ・・・
  // 検索処理
  var $list = $(targetElementsCondition);

上記は、JQueryのセレクタを使った検索処理です。
(JQueryのセレクタ: http://semooh.jp/jquery/api/selectors/>)

活性&表示されているタグのみフォーカスを当てるようにするため、
「:enabled」「:visible」「not([readonly])」のような条件で絞り込んでいます。
※AngularJSでいうと、ng-disabled、ng-hide、ng-readonly属性に対応する処理です!

条件が漏れると、遷移先のタグが表示されていないために、フォーカスがどこにも
当たらなくなってしまいます。。。

キーイベントを拾う

  return function(scope, element, attrs) {
      element.bind("keydown keypress", function (event) {
  ・・・
  var keyCode = event.which || event.keyCode;

上記の記述で、押されたキーの値が変数keyCodeに値が設定されます。
ちなみに、Enterキーは13です。

Enterキー押下時、次にフォーカス遷移するエレメントを探す

  if (keyCode === 13 && !event.shiftKey && !event.altKey) {
      var $list = $(targetElementsCondition);
      $list.each(function(index) {
          if (this.tabIndex &&
              this.tabIndex >= 0 &&
              this.tabIndex > event.target.tabIndex &&
              (!destinationTabIndex || destinationTabIndex > this.tabIndex)) {
              destinationTabIndex = this.tabIndex;
              destinationListIndex = index;
          }
      });
  }

ここでポイントとなるのは、「!event.shiftKey && !event.altKey」の条件の部分です。
Shift+Enterキー、Alt+Enterキー押下時は、異なる動作をしたいため、
上記if文の処理から除外しています。

Shift+Enterキー→フォーカスを戻す処理
Alt+Enterキー→textarea内の改行処理

ちなみに、tabindexの値がマイナスの場合はフォーカス遷移させないようにする必要があるので、
「this.tabIndex >= 0」の条件も必要です!

Shift+Enterキー押下時にフォーカスを1つ前に戻す

最初にご紹介したコードに下記のコードを加えると、Shift+Enterキーを押したときに
フォーカスを戻す処理ができます。
(符号が一部異なるだけなので、もっとスマートに書けるはずっ!)

  else if (keyCode === 13 && event.shiftKey && !event.altKey) {
      var $list = $(targetElementsCondition);
      $list.each(function(index) {
          if (this.tabIndex &&
              this.tabIndex >= 0 &&
              this.tabIndex < event.target.tabIndex &&
              (!destinationTabIndex || destinationTabIndex < this.tabIndex)) {
              destinationTabIndex = this.tabIndex;
              destinationListIndex = index;
          }
      });
      if (destinationListIndex) {
          $list.eq(destinationListIndex).focus();
          event.preventDefault();
      }
  }

Alt+Enterキーでtextarea内改行

「!event.altKey」を条件を加えることで、Alt+Enterキーが押されたときは、
上記のif文の処理がスルーされます。
スルーされると、このディレクティブを使わない場合と全く同じ処理が行われることなります。
この性質を利用し、textarea内にて改行させることができます!

spaceキーでボタン押下処理

ボタンをフォーカス遷移に含めていると、これもエンターキーでフォーカス遷移されちゃいます。
この場合、ボタンにフォーカスが当たっている状態でスペースキーを押すことで、
ボタン押下することができます。
ちなみに、上記のコードの場合、フォーカス遷移の一番最後にボタンが配置されていた場合は、
エンターキーでもボタンが押せます。
「tabindex順に入力していって最後に保存!」「途中にボタンはないよ!」というような画面では、
この話は気にしなくて良いですね!

フォーカス遷移

  $list.eq(destinationListIndex).focus();

上記でフォーカスを当てることができます。

エンジニア募集中!

ビジネスバンクグループではエンジニアを募集中しています。

弊社が採用しているテクノロジや開発環境に興味を持った方は、 ここから是非エントリー を!