結論:onChangeに関数を渡すだけ
flatpickrで選択された日付をJS側で受け取るには、初期化オプションに onChange コールバックを渡します。input の change イベントを別途監視する必要はありません。
<input type="text" id="datepicker" placeholder="日付を選択">
<div id="result"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.13/flatpickr.min.js"></script>
<script>
flatpickr("#datepicker", {
dateFormat: "Y-m-d",
onChange: function(selectedDates, dateStr, instance) {
document.getElementById("result").textContent = dateStr;
}
});
</script>
実際に動くデモです。日付を選ぶとすぐ下にonChangeが受け取った値が表示されます。
onChangeが受け取る3つの引数
コールバックには selectedDates、dateStr、instance の3つが渡されます。どれを使うかは用途次第です。
selectedDates(配列)
選択された日付のDateオブジェクトが入った配列。単一選択なら要素数1、範囲選択なら開始日と終了日の2要素、まだ何も選ばれていなければ空配列になる。日付の計算処理をするならこちらを使う。
dateStr(文字列)
dateFormat オプションに従って整形済みの文字列。画面表示やそのまま送信する値として使うなら、こちらのほうが手間がない。
instance(オブジェクト)
flatpickrのインスタンス自体。instance.input で対象のinput要素を参照できるため、同じ関数を複数のinputで使い回すときに区別する用途で使う。
素のinputの change イベントとの一番の違いは発火のタイミングです。change イベントはinput要素からフォーカスが外れて初めて発火しますが、onChange はカレンダー上で日付をクリックした瞬間に発火します。キーボード入力で日付を直接書き換えるケースを除けば、onChange のほうが実際の選択操作に忠実です。
よくあるバリエーション・ハマりどころ
onChangeとonCloseの使い分け
単一選択では気にする場面が少ないですが、範囲選択(mode: "range")では onChange と onClose で確定タイミングが異なります。onChange は開始日をクリックした時点と終了日をクリックした時点の2回発火するのに対し、onClose はカレンダーが閉じたタイミングの1回だけ発火します。
flatpickr("#range-picker", {
mode: "range",
dateFormat: "Y-m-d",
onChange: function(selectedDates, dateStr) {
// 開始日選択時と終了日選択時の計2回呼ばれる
console.log("changed:", dateStr);
},
onClose: function(selectedDates, dateStr) {
// カレンダーを閉じたタイミングの1回だけ呼ばれる
console.log("closed:", dateStr);
}
});
「範囲が確定してから1回だけAPIを叩きたい」というような処理は、onChange ではなく onClose に書いたほうが二重実行を防げます。範囲選択自体の実装方法は「flatpickrで日付の範囲選択を実装する方法」でまとめています。
取得した値をフォーム送信用に変換する
dateStr は dateFormat の書式そのままなので、画面表示用に Y年m月d日 のような日本語フォーマットを使っていると、サーバー側が期待する YYYY-MM-DD と食い違うことがあります。この場合は表示用と送信用でinputを分けるのが簡単です。
<input type="text" id="datepicker-display" placeholder="日付を選択">
<input type="hidden" id="datepicker-value" name="visit_date">
<script>
flatpickr("#datepicker-display", {
dateFormat: "Y年m月d日",
onChange: function(selectedDates, dateStr, instance) {
if (selectedDates[0]) {
var iso = instance.formatDate(selectedDates[0], "Y-m-d");
document.getElementById("datepicker-value").value = iso;
}
}
});
</script>
instance.formatDate() を使うと、表示用とは別の書式で同じ日付を再フォーマットできます。altInput: true を使う手もありますが、hidden inputで送信値を分ける方法のほうが挙動を追いやすく、他のバリデーション処理とも組み合わせやすいです。
選択解除時にselectedDatesが空になる
クリアボタンなどで選択を解除できる設定にしている場合、onChange は selectedDates が空配列の状態でも呼ばれます。selectedDates[0] を無条件に参照するとエラーになるため、上のコード例のように存在チェックを入れておくと安全です。
まとめ
flatpickrの値取得は onChange オプションに関数を渡すだけで完結し、selectedDates・dateStr・instance の3つの引数から必要な形式を選べば十分です。範囲選択で確定タイミングを1回に絞りたいときは onClose、送信用の値を別書式にしたいときは instance.formatDate() を使うと、余計な変換処理を書かずに済みます。日本語化については「flatpickrを日本語化する方法」も合わせて確認してください。
関連するUI事例
flatpickrを使った日付・時刻選択の実装例です。単一選択・範囲選択・時刻選択のパターンをまとめて確認できます。