JavaScriptによるバリデート

これまでバリデーターは、フォームに入力された内容を、サーバーに送信するとサーバーからのレスポンスとしてエラー結果が返ってくるものでした。

そこで今回は、a-blog cmsに標準で搭載されているJavaScriptを利用したバリデーター機能を利用してみたいと思います。

JavaScriptバリデーターの利点として、エンドユーザーのブラウザ側でエラーを判定するため、エラーがあったときのレスポンスが高速になるというメリットがあります。また、サーバーに余分な負荷をかけずに済むというメリットも挙げられます。

必要な作業

  1. a-blog cmsが標準で搭載しているJavaScript(acms.js)の読み込み
  2. 場合によってCSSにスタイルの追記作業
  3. この機能を使うためのクラスを付与
  4. エラーメッセージの記述を書き換え

通常のバリデーターも動かした上でJavaScriptバリデーターを動かすので、JavaScriptがOFFの環境でもエラー処理が動きます。

実装

まずは、組み込みJSを使うためにacms.jsを読み込みます。読み込みについては、こちらを参考ください。 読み込みが必要なJavascriptファイル

CSSを追記する

デフォルトの設定では、a-blog cmsのシステムのスタイルに組み込み済みですので、特に設定していただかなくても動きます。クラスを変更する場合や、スタイルを調整する場合は以下を参考に書き換えてください。

/* エラーメッセージ非表示時のスタイル */
.validator-result-,
.validator-result-1,
.v-result-,
.v-result-1 {
  display: none;
}

/* エラーメッセージ表示時のスタイル */
.validator-result-error,
.validator-result-0,
.v-result-error,
.v-result-0 {
  display: block;
  color: #F00;
}

クラスの付与

フォームでJavaScriptバリデーターを使用できるようにするために、以下のクラスをフォームに振ります。

<form action="" method="post" class="js-validator" enctype="multipart/form-data">
...
</form>

エラーメッセージの記述を書き換える

今までのエラーメッセージの記述

<th>ハンドルネーム (必須)</th>
<td>
  <input type="text" name="name" value="{name}">
  <input type="hidden" name="field[]" value="name">
  <input type="hidden" name="name:validator#required">
  <!-- BEGIN name:validator -->
  <p class="notice">ハンドルネームは必須項目です</p>
  <!-- END name:validator -->
</td>

JavaScriptバリデーターのエラーメッセージの記述

<th>ハンドルネーム (必須)</th>
<td>
  <input type="text" name="name" value="{name}">
  <input type="hidden" name="field[]" value="name">
  <input type="hidden" name="name:validator#required" id="name-v-required">
  <label for="name-v-required" class="validator-result-{name:validator#required}">
    ハンドルネームは必須項目です
  </label>
</td>
5行目id="name-v-required" を追加
6行目テンプレートタグのブロックから、label要素( classとfor属性も必須 )に変更

validator指定している要素のidと、その要素に対するエラーメッセージのラベルのfor属性を一致させてください。

JavaScriptが利用するための記述を加える事で、エラー時にlabel要素のclass名が書き換えられます。それにより、表示/非表示のCSSが操作されることでエラーメッセージとして動作します。

初期の入力画面( step )にも、再入力画面( step#reapply )と同様に サーバーに送信される前の動作なので、初期の入力画面でもエラーメッセージが表示される必要があります。再入力画面( step#reaply )と同じように書き換えましょう。インクルード機能を使い同じテンプレートを使う事をお勧めします。

組み込みJSの設定

以下のような設定が/js/config.jsで設定できます。

設定項目説明デフォルト値
validatorFormMarkバリデーターを使うform要素のセレクター'form.js-validator'
validatorResultClassエラーメッセージ要素につけるクラス'validator-result-'
validatorOkClassバリデートにパスした時につけるクラス'valid'
validatorNgClassバリデートに引っかかった場合につけるクラス'invalid'

validatorOkClassvalidatorNgClassは 該当する data-validator="フィールド名" が付与されている要素に、バリデートした結果に対して対応するクラスを付与します。

さあ、確認してみましょう

一通り編集し終わったら、動作を確認してみましょう。

JavaScriptバリデーターを利用すると画面遷移なしで即座にエラーを表示できるため、エンドユーザーに対するレスポンス向上につながります。記述は若干多くなりますが、積極的に利用してみてください。

JavaScriptバリデーターを実装したサンプルコード

<h3>お問い合わせ情報</h3>
<div class="entry-container">
<table class="contact-form">
  <tr>
    <th>
      <label for="description">ご用件</label><span class="label-required">必須</span>
      <label class="valid-mark" data-validator="description">
        <span class="acms-icon acms-icon-checklist"></span>
      </label>
    </th>
    <td>
  
      <select id="description" class="form-select" name="description[]">
        <option value="" selected="selected">選択してください</option>
        <option value="ご質問"{description:selected#ご質問}>ご質問</option>
        <option value="ご要望"{description:selected#ご要望}>ご要望</option>
        <option value="資料請求"{description:selected#資料請求}>資料請求</option>
        <option value="その他"{description:selected#その他}>その他</option>
      </select>
      <input type="hidden" name="field[]" value="description">
      <input type="hidden" name="description:v#required" id="description-v">

      <label for="description-v" class="validator-result-{description:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>お問い合わせ種類を選択してください。</p>
      </label>
    </td>
  </tr>
  <tr>
    <th>
      <label for="inquiry">お問い合わせ内容</label><span class="label-required">必須</span>
      <label class="valid-mark" data-validator="inquiry">
        <span class="acms-icon acms-icon-checklist"></span>
      </label>
    </th>
    <td>
      <textarea id="inquiry" name="inquiry" rows="5" class="acms-form-width-full" placeholder="お問い合わせ内容を入力してください。" data-validator="inquiry">{inquiry}</textarea>
      <input type="hidden" name="field[]" value="inquiry">
      <input type="hidden" name="inquiry:v#required" id="inquiry-v-required">
      <input type="hidden" name="inquiry:c" value="KV">

      <label for="inquiry-v-required" class="validator-result-{inquiry:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>お問い合わせ内容を入力してください。</p>
      </label>
    </td>
  </tr>
</table>
</div>

<h3>お客様情報</h3>
<div class="entry-container">
<table class="contact-form h-adr">
  <tr>
    <th><label for="organization">会社名</label></th>
    <td>
      <input id="organization" type="text" name="organization" autocomplete="organization" value="{organization}" class="acms-form-width-full" placeholder="株式会社サンプルサイト">
      <input type="hidden" name="field[]" value="organization">
      <input type="hidden" name="organization:c" value="KV">
    </td>
  </tr>
  <tr>
    <th>
      <label for="name">お名前</label><span class="label-required">必須</span>
      <label class="valid-mark" data-validator="name">
        <span class="acms-icon acms-icon-checklist"></span>
      </label>
    </th>
    <td>
      <input id="name" type="text" name="name" autocomplete="name" class="acms-form-width-full" value="{name}" placeholder="山田 太郎" data-validator="name">
      <input type="hidden" name="field[]" value="name">
      <input type="hidden" name="name:v#required" id="name-v-required">
      <input type="hidden" name="name:c" value="KV">

      <label for="name-v-required" class="validator-result-{name:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>お名前を入力してください。</p>
      </label>
    </td>
  </tr>
  <tr>
    <th>
      <label for="email">メールアドレス</label><span class="label-required">必須</span>
      <label class="valid-mark" data-validator="email">
        <span class="acms-icon acms-icon-checklist"></span>
      </label>
    </th>
    <td>
      <input id="email" type="email" name="email" autocomplete="email" value="{email}" class="acms-form-width-full" placeholder="info@example.com" data-validator="email">
      <input type="hidden" name="field[]" value="email">
      <input type="hidden" name="email:v#required" id="email-v-required">
      <input type="hidden" name="email:v#email" id="email-v-email">
      <input type="hidden" name="email:c" value="a">

      <label for="email-v-required" class="validator-result-{name:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>メールアドレスを入力してください。</p>
      </label>
      <label for="email-v-email" class="validator-result-{name:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>正しいメールアドレスを入力してください。</p>
      </label>
    </td>
  </tr>
  <tr>
    <th><label for="tel">お電話番号</label></th>
    <td>
      <input id="tel" type="tel" name="tel" autocomplete="tel" value="{tel}" size="12" class="acms-form-width-full" placeholder="000-000-0000">
      <input type="hidden" name="field[]" value="tel">
      <input type="hidden" name="tel:c" value="n">
    </td>
  </tr>
  <tr>
    <th><label for="address">ご住所</label><span class="label-required">必須</span></th>
    <td>
      <script src="https://yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
      <span class="p-country-name" style="display:none;">Japan</span>
      <div class="acms-form-group">
        〒<input type="text" name="postal-code" autocomplete="postal-code" value="{postal-code}" id="postal-code" class="acms-form-width-mini p-postal-code" size="8" maxlength="7" placeholder="0000000" data-validator="postal-code">
        <input type="hidden" name="field[]" value="postal-code">
        <input type="hidden" name="postal-code:c" value="a">

        <select class="form-select p-region" name="address-level1" autocomplete="address-level1">
          <option value="" selected="selected">都道府県</option>
          <option value="北海道"{address-level1:selected#北海道}>北海道</option>

          <option value="青森県"{address-level1:selected#青森県}>青森県</option>
          <option value="岩手県"{address-level1:selected#岩手県}>岩手県</option>
          <option value="宮城県"{address-level1:selected#宮城県}>宮城県</option>
          <option value="秋田県"{address-level1:selected#秋田県}>秋田県</option>
          <option value="山形県"{address-level1:selected#山形県}>山形県</option>
          <option value="福島県"{address-level1:selected#福島県}>福島県</option>
          <option value="茨城県"{address-level1:selected#茨城県}>茨城県</option>
          <option value="栃木県"{address-level1:selected#栃木県}>栃木県</option>
          <option value="群馬県"{address-level1:selected#群馬県}>群馬県</option>

          <option value="埼玉県"{address-level1:selected#埼玉県}>埼玉県</option>
          <option value="千葉県"{address-level1:selected#千葉県}>千葉県</option>
          <option value="東京都"{address-level1:selected#東京都}>東京都</option>
          <option value="神奈川県"{address-level1:selected#神奈川県}>神奈川県</option>
          <option value="新潟県"{address-level1:selected#新潟県}>新潟県</option>
          <option value="富山県"{address-level1:selected#富山県}>富山県</option>
          <option value="石川県"{address-level1:selected#石川県}>石川県</option>
          <option value="福井県"{address-level1:selected#福井県}>福井県</option>
          <option value="山梨県"{address-level1:selected#山梨県}>山梨県</option>

          <option value="長野県"{address-level1:selected#長野県}>長野県</option>
          <option value="岐阜県"{address-level1:selected#岐阜県}>岐阜県</option>
          <option value="静岡県"{address-level1:selected#静岡県}>静岡県</option>
          <option value="愛知県"{address-level1:selected#愛知県}>愛知県</option>
          <option value="三重県"{address-level1:selected#三重県}>三重県</option>
          <option value="滋賀県"{address-level1:selected#滋賀県}>滋賀県</option>
          <option value="京都府"{address-level1:selected#京都府}>京都府</option>
          <option value="大阪府"{address-level1:selected#大阪府}>大阪府</option>
          <option value="兵庫県"{address-level1:selected#兵庫県}>兵庫県</option>

          <option value="奈良県"{address-level1:selected#奈良県}>奈良県</option>
          <option value="和歌山県"{address-level1:selected#和歌山県}>和歌山県</option>
          <option value="鳥取県"{address-level1:selected#鳥取県}>鳥取県</option>
          <option value="島根県"{address-level1:selected#島根県}>島根県</option>
          <option value="岡山県"{address-level1:selected#岡山県}>岡山県</option>
          <option value="広島県"{address-level1:selected#広島県}>広島県</option>
          <option value="山口県"{address-level1:selected#山口県}>山口県</option>
          <option value="徳島県"{address-level1:selected#徳島県}>徳島県</option>
          <option value="香川県"{address-level1:selected#香川県}>香川県</option>

          <option value="愛媛県"{address-level1:selected#愛媛県}>愛媛県</option>
          <option value="高知県"{address-level1:selected#高知県}>高知県</option>
          <option value="福岡県"{address-level1:selected#福岡県}>福岡県</option>
          <option value="佐賀県"{address-level1:selected#佐賀県}>佐賀県</option>
          <option value="長崎県"{address-level1:selected#長崎県}>長崎県</option>
          <option value="熊本県"{address-level1:selected#熊本県}>熊本県</option>
          <option value="大分県"{address-level1:selected#大分県}>大分県</option>
          <option value="宮崎県"{address-level1:selected#宮崎県}>宮崎県</option>
          <option value="鹿児島県"{address-level1:selected#鹿児島県}>鹿児島県</option>

          <option value="沖縄県"{address-level1:selected#沖縄県}>沖縄県</option>
        </select>
        <input type="hidden" name="field[]" value="address-level1">
      </div>
      <textarea id="address" name="address" rows="2" class="acms-form-width-full p-locality p-street-address p-extended-address" data-validator="address">{address}</textarea>
      <input type="hidden" name="field[]" value="address">
      <input type="hidden" name="postal-code:v#required" id="postal-code-v-required">
      <input type="hidden" name="postal-code:v#regex" value="^[\d]\{7\}$" id="postal-code-v-regex">
      <input type="hidden" name="address-level1:v#required" id="address-level1-v-required">
      <input type="hidden" name="address:v#required" id="address-v-required">
      <input type="hidden" name="address:c" value="KV">

      <label for="postal-code-v-required" class="validator-result-{postal-code:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>郵便番号が入力されていません。</p>
      </label>
      <label for="postal-code-v-regex" class="validator-result-{postal-code:v#regex}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>郵便番号はハイフンなしの数値7桁で入力してください。</p>
      </label>
      <label for="address-level1-v-required" class="validator-result-{address-level1:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>都道府県が選択されていません。</p>
      </label>
      <label for="address-v-required" class="validator-result-{address:v#required}">
        <p class="error-text"><span class="acms-icon acms-icon-attention"></span>住所が入力されていません。</p>
      </label>
    </td>
  </tr>
</table>
</div>