【jQuery】 クライアントサイドの検証処理/バリデーション ~ Parsley編 ~

■ はじめに

https://blogs.yahoo.co.jp/dk521123/37666873.html
https://blogs.yahoo.co.jp/dk521123/37668489.html
の続き。

はじめ、jQuery Validation Plugin を使おうとしてたが
Bootstrap4 に対応させたく、調べてたら、Parsley が見つかったのでメモ。

■ Parsley

Parsley = パセリ
 * JavaScript によるデータ検証ツール

特徴

 * jQuery (>= 1.8) が必要
 * 古いブラウザ(IE8)もサポート(es5-shimが必要)
 * 日本語対応もOK
 * MIT
https://raw.githubusercontent.com/guillaumepotier/Parsley.js/master/LICENSE

公式サイト

http://parsleyjs.org/
デモ
http://parsleyjs.org/doc/examples.html
API
http://parsleyjs.org/doc/

■ サンプル

例1:Hello World

<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="utf-8">
<title>Demo</title>
<head>
<body>
<div id="error-message"></div>
<form id="sample-form">
<label for="sample-data">Sample data</label>
<input id="sample-data-id" name="sample-data" type="text" required
 data-parsley-error-message="エラー" data-parsley-errors-container="#error-message"><br />
<button type="submit">Click Me!</button>
</form>
<script type="text/javascript"
  src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
  integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
  crossorigin="anonymous"></script>
<script type="text/javascript" src="">https://cdn.jsdelivr.net/npm/parsleyjs@2.8.1/dist/parsley.min.js">
<script type="text/javascript">
$(function () {
  $("#sample-form").parsley();
});
</script>
</body>
</html>

例2: With Bootstrap 4 and Font Awesome

<!doctype html>
<html lang="jp">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
    <!-- icon -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
    <title>Demo</title>
  </head>
  <body>
    <div class="container">
      <h1 id="title">Bootstrap4 with Parsley</h1>
      <div id="result"></div>
      <form id="sample-form" action="" method="post" role="form">
        <div class="form-row form-group">
          <div class="col-md-4 mb-3">
            <label for="validationCustom01">名字</label>
            <input type="text" class="form-control" id="validationCustom01" placeholder="名字" name="familyName" autocomplete="yes"
             required data-parsley-errors-messages-disabled>
              <div class="invalid-feedback bs-callout bs-callout-warning hidden">
                <i class="fas fa-exclamation-triangle"></i> 名字を入力してください
              </div>
          </div>
          <div class="col-md-4 mb-3">
            <label for="validationCustom02">名前</label>
            <input type="text" class="form-control" id="validationCustom02" placeholder="名前" name="firstName" autocomplete="yes"
            required data-parsley-errors-messages-disabled>
              <div class="invalid-feedback bs-callout bs-callout-warning hidden">
                <i class="fas fa-exclamation-triangle"></i> 名前を入力してください
              </div>
          </div>
          <div class="col-md-4 mb-3">
            <label for="validationCustomUsername">ユーザー名</label>
            <div class="input-group">
              <div class="input-group-prepend">
                <span class="input-group-text" id="inputGroupPrepend">@</span>
              </div>
              <input type="text" class="form-control" id="validationCustomUsername" name="userName" placeholder="ユーザー名"
               aria-describedby="inputGroupPrepend" required data-parsley-errors-messages-disabled>
              <div class="invalid-feedback bs-callout bs-callout-warning hidden">
                <i class="fas fa-exclamation-triangle"></i> ユーザー名を入力してください
              </div>
            </div>
          </div>
        </div>
        <div class="form-row form-group">
          <div class="col-md-6 mb-3">
            <label for="validationCustomDateStart">開始日</label>
            <input type="date" class="form-control" id="validationCustomDateStart" name="startDate" placeholder="開始日"
             required data-parsley-errors-messages-disabled>
            <div class="invalid-feedback bs-callout bs-callout-warning hidden">
              <i class="fas fa-exclamation-triangle"></i> 開始日を入力してください
            </div>
            <div id="invalidDateStartErrorMessage"></div>
          </div>
          <div class="col-md-6 mb-3 form-group">
            <label for="validationCustomDateEnd">終了日</label>
            <input type="date" class="form-control" id="validationCustomDateEnd" name="endDate" placeholder="終了日"
              data-parsley-custom-end-date-validation="" data-parsley-errors-messages-disabled>
            <div class="invalid-feedback bs-callout bs-callout-warning hidden">
              <i class="fas fa-exclamation-triangle"></i> 開始日より未来日付は指定できません
            </div>
            <div id="invalidDateEndErrorMessage"></div>
          </div>
        </div>
        <div class="form-row">
          <div class="col-md-12 mb-3 form-group">
            <label for="validationCustomUsername">メモ</label>
            <div class="input-group">
              <textarea id="validationMemo" class="form-control" name="memo" placeholder="メモ" rows="3" maxlength="200" required
               required data-parsley-errors-messages-disabled></textarea>
            <div class="invalid-feedback bs-callout bs-callout-warning hidden">
              <i class="fas fa-exclamation-triangle"></i> メモを入力してください
            </div>
              <div id="invalidMemoErrorMessage"></div>
            </div>
          </div>
        </div>
        <div class="form-group">
          <div class="form-check">
            <input class="form-check-input" type="checkbox" value="" id="invalidCheck" name="agreement" required
            required data-parsley-errors-messages-disabled>
            <label class="form-check-label" for="invalidCheck">
              利用規約に同意する
            </label>
            <div class="invalid-feedback bs-callout bs-callout-warning hidden">
              <i class="fas fa-exclamation-triangle"></i> 利用規約に同意していただき、チェックを入れる必要があります
            </div>
          </div>
        </div>
        
        <button type="submit" class="btn btn-primary">フォームを送信</button>
      </form>
    </div>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
    <!-- Parsley -->
    <script type="text/javascript" src="">https://cdn.jsdelivr.net/npm/parsleyjs@2.8.1/dist/parsley.min.js">
    <script type="text/javascript">
    $(function () {
      $("#sample-form").parsley({
        errorClass: 'is-invalid text-danger',
        successClass: 'is-valid',
        errorsContainer: function(ParsleyField) {
            return ParsleyField.$element.parents('.form-group');
        },
        errorsWrapper: '<span class="form-text text-danger"></span>',
        errorTemplate: '<span></span>',
        trigger: 'change'
      }).on('field:validated', function() {
        var isValid = $('.parsley-error').length === 0;
        $('.bs-callout-info').toggleClass('hidden', !isValid);
        $('.bs-callout-warning').toggleClass('hidden', isValid);
      });
    });
    
    window.Parsley.on('form:submit', function() {
      $("#result").text("[OK!] Values are valid!");
      return false; // Don't submit for this demo
    });
    window.Parsley.addValidator('customEndDateValidation', {
      validateDate: function(value) {
        console.log("Event Fired");
        return isValidDates();
      }
    });

    function isValidDates() {
      console.log("Enter...");
      var inputCustomDateEnd = document.getElementById("validationCustomDateEnd");
      inputCustomDateEnd.setCustomValidity("");
       
       var endDateValue = $("#validationCustomDateEnd").val();
       if (!endDateValue) {
          return true;
       }
       var startDate = new Date($("#validationCustomDateStart").val());
       var endDate = new Date(endDateValue);
       if (endDate < startDate) {
          console.log("Error");
          return false;
       }
       
       return true;
    }
    </script>
  </body>
</html>

■ Parsley あれこれ

【1】 エラー結果をクリアにする

* モーダルで入力フォーム作って、エラーの後に、キャンセルして、再度、モーダル開いたら、エラーのままだったので、モーダル表示前にリセットしたい
$('#sample-form').parsley().reset();

【2】 時間の検証

[[http://parsleyjs.org/doc/index.html#validators-list]]
によると、formタグの Required や type="email" などは対応されており
Parsley.js 側で自動的に対応されているようだが、
type="time"には対応されていないようなので、
hh:mm形式になるように時間検証を行う
対応案 : inputタグのpatternを使用して正規表現で検証する
<input type="time" class="form-check-input" pattern="^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$">

【3】 独自の検証

 * 上記の「例2: With Bootstrap 4」で使用
作成方法
[1] 対象の入力欄に「data-parsley-【独自の名前】」を追加(例だと「custom-end-date-validation」)
 ~~~~~
 <input ... data-parsley-custom-end-date-validation=""
 ~~~~~

[2] 独自検証するイベントを追加(以下の「'customEndDateValidation'」は[1]と紐づくように)
 ~~~~~
 window.Parsley.addValidator('customEndDateValidation', {
  validateString: function(value) {
    return 【判定文(true/false)】;
  }
 });
 ~~~~~
公式デモ
http://parsleyjs.org/doc/examples/customvalidator.html
公式ドキュメント 「Custom Validators」
[[http://parsleyjs.org/doc/index.html#custom]]


関連記事

クライアントサイドの検証処理 / バリデーション ~ Bootstrap4編 ~

https://blogs.yahoo.co.jp/dk521123/37666873.html

クライアントサイドの検証処理 / バリデーション ~ HTML5+JS編 ~

https://blogs.yahoo.co.jp/dk521123/37668489.html

Bootstrap 4 ~ 入門編 ~

https://blogs.yahoo.co.jp/dk521123/28015251.html

アイコン を 表示する ~ Font Awesome

https://blogs.yahoo.co.jp/dk521123/35506135.html