ホーム DoRuby datetimepickerでの、あり得ない日付の入力制御の覚え書き

datetimepickerでの、あり得ない日付の入力制御の覚え書き

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

railsのビューで、フォームを使って日付を入力させたい時、

datetimepickerを使っていました。

datetimepickerはJSでテキストフィールドに付加する事で、カレンダー表示で日付・時間を選択させる事のできる便利なプラグインです。

ただ、テキストエリアに追加するので、ユーザーがテキストフィールドに直接日付を入力する事も出来てしまいます。

それ自体は別に問題ない事ですが、日付じゃないテキストや、あり得ない日付を入力されてしまう場合もあります。

日付じゃないテキストについては、datetimepickerが勝手に判断してテキストフィールドの中を空に置き換えてくれるのですが、

あり得ない日付に関しては、

「2000-04-31」-> 「2000-05-01」に変換してくれる

「2000-05-32」-> 変換してくれない!

となるので、フォームでもらった値を、

モデルインスタンスのDateTime型のカラムに代入しようとするとエラーを吐きます。

@model = Model.new(date: param[:model][:date])
 -> ArgumentError

どうやら31日までは,datetimepicker側で勝手に判断して変換してくれるようですが、

32日を超えると「ありえない日付」となり、変換はしてくれないようです。

これでは困るので、色々と解消しようとした顛末です。

 1. validationで弾けないか?

モデルにvalidateを設置して、フォームを送ったら「不正な値です」などのアラートを表示させたいと思いましたが、

よくよく考えると、validate発火前の、インスタンスへの代入時点でエラーになっているので、ちょっと厳しそうです。

コントローラの方でチェックするのも考えましたが、フォームを使うコントローラ全てにチェックを入れないといけなかったりするので、

あまり良くなさそうです。

 2. JSで弾く(onBlur編)

そもそもそのような入力が出来なければ良い話なので、JSで入力制御を入れる事にしました。

ちなみに、datetimepicker導入部のJSはこんな感じ。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

今回は日付だけ取りたいので、時間までは取らないようにしています。

このままだと入力制御がかかってないので、onBlurのイベントハンドラを使ってみます。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

$('.date_text_field').onBlur = function(){
  if ($(this).val() != '') {
	  var inputDate = new Date($(this).val());
	  if (isNaN(inputDate.getTime())) {
	    $(this).val('');
	  }
  }	
}

「isNaN(inputDate.getTime())」でテキストフィールドに入力された値が日付として正当か判断しています。

これでテキストフィールドに「2000-03-34」のようなおかしい日付を入力して、フォーム送信ボタンを押すと・・・・

テキストフィールドの中身が空になりました!

・・・しかし、onBlurを使っているので、テキストフィールドからフォーカスが外れれば空になってくれるのですが、

テキストフィールドに入力した状態で、エンターキーを押してそのままフォーム送信したりすると、、

フォーカスは外れないので、そのまま値が送られてしまい、やはりArgumentErrorになってしまいました。

 3. JSで弾く(onsubmit編)

ならば、フォーム全体がsubmitされたタイミングで入力判定すれば良いじゃないか!

という訳で、フォーム全体のイベント監視をさせるようにしてみます。

$('.date_text_field').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
});

$('form').on('submit', function(){
  picker();
 });

function picker(){
  $('.date_text_field').each(function(){
    if ($(this).val() != '') {
      var inputDate = new Date($(this).val());
      if (isNaN(inputDate.getTime())) {
        $(this).val('');
      }
    }
  });
}

formタグを監視するようにしてみました。

フォームがsubmitされると、date_text_fieldクラスを探し出し、日付として不正の場合値を空にします。

これで再度日付入力用のテキストフィールドに「2000-03-34」を入力してフォーム送信・・・

-> 送信直前にフォームの内容が空になりました!

 4. JSで弾く(解決編)

上記の方法で良いかと思ったのですが、

一画面に複数formタグがあったときは、そもそもformにJS監視させたくないときは?などの疑問が残ります。

そんな中、とてもスマートな解決法を教えて頂きました。

$('.picker_date').datetimepicker({
  format: 'YYYY-MM-DD',
  language: 'ja'
}).on('dp.error', function(e) {
  $(e.target).val('');
});

これだけです。formに対してのイベントリスナーもいりません。

dp.errorイベントを拾うことで、入力された値に不整合があると、値を空にすることが出来ます。

フォーム送信時だけでなく、テキストフィールドからフォーカスが移ったときにも評価が走ります。

ということで無事、datetimepickerへの入力制御を入れる事が出来ました!

記事を共有
モバイルバージョンを終了