jQuery 「↓」、「↑」キーでinputのフォーカスを移動させる

何がやりたいか

縦にテキストボックスが並んでいるフォームがあるとします

<table>
<tr>
<td>
<input type="text" class="sample-input" id="sample64">
</td>
<tr>
<tr>
<td>
<input type="text" class="sample-input" id="sample256">
</td>
<tr>
<tr>
<td>
<input type="text" class="sample-input" id="sample512">
</td>
<tr>
<tr>
<td>
<input type="text" class="sample-input" id="sample128">
</td>
<tr>
</table>

イメージはこんな感じ
スクリーンショット 2017-05-12 10.41.55.png

この各input間を「↓」、「↑」キーで移動できるようにしたいのです。
(実際には左右にもinputがあり、tabでは移動できない画面です)

各機能

「↓」、「↑」のイベント取得

keydownイベントそ取得してなんのキーが押されたかをkeyCodeを使って調べるだけです。
keyCodeは以下の通り。

keyCode キー
37
38
39
40

ソースはこんな感じ。

// 対象フォーム群のキーダウンイベントを取得
$(".sample-input").on("keydown", function(e) {
if(e.keyCode === 40) {
// 「↓」キーが押されました
}else if(e.keyCode === 38) {
// 「↑」キーが押されました
}
});

フォーカスの移動

.focus()で指定した要素にフォーカスを移動できる。

$("#id").focus();

問題発生

ちょっと待て

今回のフロントの実装では、連番ではなくDBのID(以後「d_id」と呼ぶ)をinputのidに付与していたので

<input type="text" class="sample-input" id="sample64←ココ!">

id+1とかで次を指定できない

強引に問題解決

一番良かったのは、idの前方一致で$(this)の次の要素が取得すること(感じ取ってくださいw)。
でもちょっと実装が思い浮かばなかったので強引に解決!
そうだ、d_idリストを用意してしまおう

// d_idリストを用意
// d_id_list = [64, 256, 512, 128]
// (今回はPHPで実装しています)
var d_id_list = [];
<?php
$set = '';
foreach ($array as $value) {
if($set){
$set .= ',';
}
$set .= $value;
}
echo "d_id_list = [{$set}];";
?>

完成

全てを合体させて完成したのが以下のソース

// d_idリストを用意
// d_id_list = [64, 256, 512, 128]
// (今回はPHPで実装しています)
var d_id_list = [];
<?php
$set = '';
foreach ($array as $value) {
if($set){
$set .= ',';
}
$set .= $value;
}
echo "d_id_list = [{$set}];";
?>
// 対象フォーム群のキーダウンイベントを取得
$(".sample-input").on("keydown", function(e) {
// キーダウンイベントを検知した要素のidからd_idを取得
// その値とd_idリストを使用してd_idリストのindexを取得する
d_id_list_index = d_id_list.indexOf(Number($(this).attr("id").replace("sample","")));
// 「↓」キーが押された && 最終要素ではない
if(e.keyCode === 40 && d_id_list_index < d_id_list.length-1) {
// d_idリストと先ほど取得したd_idリストでの自分のindexを使用して1つ下のinputへfocusを移す
$("#sample"+d_id_list[d_id_list_index+1]).focus();
// 「↑」キーが押された && 最初の要素ではない
}else if(e.keyCode === 38 && d_id_list_index > 0) {
// d_idリストと先ほど取得したd_idリストでの自分のindexを使用して1つ上のinputへfocusを移す
$("#sample"+d_id_list[d_id_list_index-1]).focus();
}
});

これが一番スマートではないと思います