#命題
JavaScriptを使って、二つ(以上)ある<input type="date">
の一方が更新されたとき、もう片方を同じ値にしたい。
ブラウザはChrome 83を使用。
##想定される使用例
検索期間を2組の<input type="date">
で表し、例えば検索終了日を変更した際に、検索開始日より過去の日付だったら開始日を終了日と同じにする。
<div>
検索期間: <input id="DateSince" name="DateSince" type="date" value="2020-07-10">
~
<input id="DateUntil" name="DateUntil" type="date" value="2020-07-10">←こちらを変更すると左側の日付も変わります。
</div>
具体的には上記のコードで、DateUntilを2020-7-09に変更した場合、DateSinceも2020-7-09に書き換わるようにする。
実際の実装では逆の処理(DateSinceをDateUntilより未来にした場合、DateUntilをDateSinceと同じ値にする)も必要だが、説明簡略化のために省く。
#具体的な方法
イベント自体の作成は簡単。
function dateUntilChanged(e) {
const dateSince = document.getElementById("DateSince");
const value = e.target.value;
if (dateSince.value < value) {
dateSince.value = value;
}
}
問題はこのイベントをどのタイミングで発火させるかである。
##ダメな例: changeイベントを使う
変更されたのなら素直にchange
イベントを使えばいいじゃん、とついつい考えてしまいがちだが、それは残念ながら間違い。
document.getElementById("DateUntil").addEventListener("change", dateUntilChanged);
こうすると~~(少なくともChromeでは)~~DateUntilが打鍵されるたびにイベントが発火するので、「2020」とキーボード入力する際に2→0→2→0と入力するためにDateSinceが0002年になってしまう(当然、日付の変更条件は満たされなくなるので、0002年のまま変更されない)。
この動作は正直言って好ましくない。イベントをいちいち発火するコストも問題だ。
##よりよい例: blur(フォーカスアウト)イベントを使う
入力されるたびにイベントを発生させるのではなく、Dateの入力が完了した後、Tabキーや<input type="date">
の外部をクリックすると起こるようなイベントがあればいい。
そこで登場するのがblurイベントだ。
blurといきなり言われても分かりづらいので(個人的にはブリットポップのバンドを思い出す)説明すると、ある要素からフォーカスが外れた際に(別のところをクリックするなど)発生するイベントのこと。
要はblur(ぼやけるの意)がfocusの対義語だから、フォーカスアウトするイベントをそう呼んでいるらしい。
// 前掲例のchangeをblurに変えただけ
document.getElementById("DateUntil").addEventListener("blur", dateUntilChanged);
~~Chromeでは、~~デートピッカーを抜け出しただけではblurイベントが発生しないので注意!
(<input type="date">
の年の部分が選択されているため)
ほかの箇所をクリックした時点でblurが発火するので、実用上はそこまで問題ではない。
私が使った場面は<form>
で検索期間を指定して「検索」ボタン押下というシナリオだったので、この問題は無視できた。
#おさらい(CodePen)
See the Pen Javascriptで日付の連動更新をする by Nagayama Toshiaki (@NagayamaToshiaki) on CodePen.
#参考文献
holstetoさんの回答(英語)
javascript - HTML5 <input type=“date”> - onChange Event - Stack Overflow
<input type="date">
が変更された際に発生するイベントについてまとめられています。
この回答に出会わなければこの記事を書けませんでした。
#追記
Firefox 78でも同様の挙動が確認できたので、一部取り消し線を入れました。