【jQuery Validation Plugin】日付のバリデーション(現在より未来、終了日を開始日より未来を検証)

f:id:bonoponz:20201023120720p:plain

もくじ

環境

  • Laravel 7
  • PHP 7
  • jQuery v3.5.1
  • bootstrap 4
  • jQuery Validation Plugin – v1.19.1
  • datetime picker(Tempus Dominus版)

今回、日付を入力するにあたってライブラリ(datetime picker)を使用しています。

bonoponz.hatenablog.com

全体像

<form action="/" id="postForm" method="POST">
@csrf

  <div class="form-group">
    <label for="formTitle" class="col-form-label">タイトル</label>
    <input type="text" class="form-control" id="formTitle" name="formTitle" placeholder="タイトル"/>
  </div>

  <div class="form-group">
    <label for="startDate" class="col-form-label">開始日時</label>
    <div class="input-group date" id="datetimepicker_startDate" data-target-input="nearest">
      <input type="text" class="form-control datetimepicker-input" id="startDate" name="startDate" data-target="#datetimepicker_startDate"/>
      <div class="input-group-append" data-target="#datetimepicker_startDate" data-toggle="datetimepicker">
        <div class="input-group-text"><i class="far fa-calendar-alt"></i></div>
      </div>
    </div>
  </div>

  <div class="form-group">
    <label for="endDate" class="col-form-label">終了日時</label>
    <div class="input-group date" id="datetimepicker_endDate" data-target-input="nearest">
      <input type="text" class="form-control datetimepicker-input" id="endDate" name="endDate" data-target="#datetimepicker_endDate"/>
      <div class="input-group-append" data-target="#datetimepicker_endDate" data-toggle="datetimepicker">
        <div class="input-group-text"><i class="far fa-calendar-alt"></i></div>
      </div>
    </div>
  </div>

  <div class="form-group row justify-content-center">
    <button type="submit" name="send" class="btn btn-primary">送信</button>
  </div>
</form>
<script type="text/javascript">
$(function(){
  $('#postForm').validate({
    rules: {
      formTitle: {
        required: true,
        maxlength: 10,
      },
      startDate: {
        required: true,
        afterNow: true,
      },
      endDate: {
        required: true,
        afterStartDate: true,
      },
    },
    messages: {
      formTitle: {
        required: 'タイトルを入力してください。',
        maxlength: 'タイトルは10字以内でお願いします。',
      },
      startDate: {
        required: '開始日時を入力してください。',
      },
      endDate: {
        required: '終了日時を入力してください。',
      },
    },
    errorPlacement: function(error, element){
      var errorKey = $(element).attr('id') + 'Error';
      $('#error_' + errorKey).remove();
      element.addClass('is-invalid');
      const errorP = $('<p>').text(error[0].innerText);
      const errorDiv = $('<div class="invalid-feedback" id="error_' + errorKey + '">').append(errorP);
      element.parent().append(errorDiv);
    },
    success: function(error, element) {
      var errorKey = $(element).attr('id') + 'Error';
      $('#error_' + errorKey).remove();
      $(error).remove();
      $(element).removeClass('is-invalid');
      $(element).removeClass('error');
    },
  });

  var now = moment(new Date()).format("YYYY/MM/DD HH:mm");
  $.validator.addMethod(
    "afterNow",
    function(value, element) {
      return now < $('#startDate').val()
    },
    "開始日時は現在より未来にしてください。"
  );
  $.validator.addMethod(
    "afterStartDate",
    function(value, element) {
      return $('#startDate').val() < $('#endDate').val()
    },
    "終了日時は開始日時より未来にしてください。"
  );
});

初期表示 f:id:bonoponz:20201025122234p:plain

未入力

f:id:bonoponz:20201025122246p:plain

指定した日付より未来ではない

f:id:bonoponz:20201025122257p:plain

addMethod()

addMethod()を用いて、日付のバリデーションを設定します。

jQuery.validator.addMethod( name, method [, message ] )

コールバック関数を使っていますね。コールバック関数が理解できないと少し理解に苦しいかもしれませんが、もしよくわからなくてもあまり深く考えないようにしましょう!

参考:https://jqueryvalidation.org/jQuery.validator.addMethod/

現在より未来

var now = moment(new Date()).format("YYYY/MM/DD HH:mm");
$.validator.addMethod(
  "afterNow",
  function(value, element) {
    return now < $('#startDate').val()
  },
  "開始日時は現在より未来にしてください。"
);

現在時刻を取得

var now = moment(new Date()).format("YYYY/MM/DD HH:mm");

今回、datetime picker(Tempus Dominus版)を使用しているので、moment()を使用して現在時刻を取得しています。

これは、addMethod()のスコープ外で定義します。

未来か検証

$.validator.addMethod(
  // name:このバリデーションに名前をつける
  "afterNow",
  // method:カスタム検証メソッドを追加する
  function(value, element) {
    return now < $('#startDate').val()
  },
  // message:このメソッドに対して表示されるメッセージを追加
  "開始日時は現在より未来にしてください。"
);

rulesaddMethod()メソッドで独自に作ったafterNowというコールバック関数を呼び出し、返り値がtrueのときにバリデーションされます。

messagesafterNowメソッド内で指定しているので、validate()では不要になります。

rules: {
  startDate: {
    required: true,
    afterNow: true, // ★ここ
  },
},
messages: {
  startDate: {
    required: '開始日時を入力してください。',
  },
},

これで現在より未来であるかのバリデーションが設定できました。

コールバック関数

function(value, element) {
  return now < $('#startDate').val()
},

ここはいわゆるコールバック関数です。jQuery Validation Pluginの公式ドキュメントに当然の如く使われていて私を悩ませた諸悪の根源なので、少しだけ触れておきます。

function(value, element)にあるvalueelementってどこにも使ってる気配ないのに何故引数として持っているんだろう、と悩みましたが、今回でいうと全く必要のない引数になります。

jQuery Validation Pluginが、それらを使うかもしれない場面を想定して用意してくれている引数になります。

value:検証された要素の現在の値

element:検証する要素、<input>などの要素すべて

深く考えずにとりあえずそうなっているんだと頭の片隅に置いておく程度で十分でしょう。

終了日は開始日より未来

現在日時より未来かどうかバリデーションしたときと同様です。

判定する対象が、現在なのか開始日時なのかの違いです。

$.validator.addMethod(
  "afterStartDate",
  function(value, element) {
    return $('#startDate').val() < $('#endDate').val()
  },
  "終了日時は開始日時より未来にしてください。"
);
rules: {
  endDate: {
    required: true,
    afterStartDate: true,
  },
},

完成です。

参考URL

.validate() | jQuery Validation Plugin