⚠️

[a-blog cms]Formモジュールとバリデーションのあれこれ 

2023/12/11に公開

前書き

このエントリーはa-blog cms Advent Calendar 2023 11日目の記事です。

今回は、ただa-blog cmsの組み込みJSを使ってバリデーションをするだけではなく、いくつかのポイントと応用を紹介していきます。

※a-blog cmsの動作テストはv3.1.5で行っております。
※a-blog cmsにはバリデータがサーバーサイドと組み込みJSの2種類あるので、それぞれ「SSバリデータ」と「JSバリデータ」と表現いたします。

本題

組み込みJSのバリデーションについて

組み込みJSとはa-blog cmsの標準で搭載してあるJavaScriptで、その中にバリデータが入っています。(公式サイトはこちら

使い方は以下で、ポイントはどのクラス/data属性に何の値を入れるかです。

  1. formタグに js-validator クラス
  2. SSバリデータにid属性
  3. (2)につけたid属性の値をエラー文にdata-validator-label属性
  4. 同じくエラー文に data-validator属性
  5. 同じくエラー文にvalidator-result-{ここにはSSバリデータのnameが入ります}クラス
  6. JSバリデータで設定するクラスをつけたい箇所にdata-validator属性

(1)はformタグにつけてください。
(2)(3)(4)は同じid値を入れてください。
(4)はなくても動作しますが、付けることでフォーカスから外れた時点で動作します。
(5)がデフォルトでは表示非表示をしてくれていて、{}にはSSバリデータのnameが入ります。
後に出てくるvalidatorOkClass validatorNgClassの付与先で、入力するinputのnameが入ります。
(6)もなくても動作しますが、後々あった方が扱いやすい場面が出てきます。

とりあえず、設定を変更していなければ上記の手順で動作します。

サンプル
<dl data-validator="name">
  <dt>名前</dt>
  <dd>
    <input
      type="text"
      name="name"
      value="{name}"
      placeholder="名前を入力してください">
  </dd>
<!-- エラー文 -->
  <dd>
    <p
      class="validator-result-{name:v#required}"
      data-validator="name-v-required"
      data-validator-label="name-v-required">
      ※お名前を入力してください
    </p>
  </dd>
<!-- / -->
  <dd hidden>
    <input type="hidden" name="name:v#required" id="name-v-required">
    <input type="hidden" name="field[]" value="name" />
  </dd>
</dl>

組み込みJSのコンフィグ

組み込みJSは /js/config.js で初期設定が行われていますが、テーマ毎に設定を変更したい場合もあるため、テーマ内で設定を上書きすることが推奨されています。

ACMS.Config({
    validatorFormMark: 'form.js-validator',
    validatorResultClass: 'validator-result-',
    validatorOkClass: 'valid',
    validatorNgClass: 'invalid'
});
設定項目 説明
validatorFormMark バリデーターを使うform要素のセレクター
validatorResultClass バリデーション実行後に要素につけるクラス属性(エラーメッセージの表示切り替えに利用できます。)
validatorOkClass バリデートにパスした時につけるクラス
validatorNgClass バリデートに引っかかった場合につけるクラス

エラー箇所まで戻る

ここまでは公式ドキュメントにも書いてありますが、ここからは応用編として進めていきます。
ポイントは、使い方(6)でつけたdata属性とコンフィグのvalidatorNgClassです。

動作の流れは、送信ボタンを押した時にvalidatorNgClassがついているかどうかを確認します。
また、使い方(6)の要素にクラスを一つつけておきましょう(ここではjs-validate)。そうすることで、楽にエラー箇所を取得できるようになります。

以下、動作の流れです。

  1. ボタンクリック時にチェックできるようにする。
  2. クリックした後にJSバリデータが動作するので、validatorNgClassの付与に時間がかかってしまい、エラーチェックを抜けてしまう場合がある。なので、setTimeout関数で時間を空ける。
  3. もしエラーがあった場合、使い方(6)で指定した箇所にvalidatorNgClassのクラスが付与されている。
  4. 前文でつけたクラス(js-validate)とvalidatorNgClassのクラスでquerySelector関数を実行すると、はじめに取得した一致箇所が取得できる。
  5. JavaScriptのscrollTo関数でエラー箇所まで戻る。
サンプル
function errCheck() {
    setTimeout(() => {
        const errText = document.querySelector('.js-validate.invalid');
        if(!errText) return true;

        const targetTop = errText.getBoundingClientRect().top + window.scrollY;
        window.scrollTo({
            top: targetTop,
            behavior: 'smooth'
        });
    }, 100);

  return false;
}

const buttonList = document.querySelectorAll('button[name="ACMS_POST_Form_Confirm"]');
buttonList.forEach((button) => {
    button.addEventListener('click', errCheck);
});

Formモジュールのstepを選べるようにする

最後に応用2です。
フォームのstepを選べるようにする場合、通常の実装をしようとするとその分formを増やす必要があります。
しかしそうしてしまうと、JSバリデータは入力欄がある方のformタグにしか反応しないです。
ですので、stepをsubmitにしてしまいます。

実際のコードを見た方がわかりやすいと思います。

サンプル
<form
	action=""
	method="post"
	class="js-validator"
	enctype="multipart/form-data">
	<input type="hidden" name="ACMS_POST_Form_Confirm" value="next">
	<input type="hidden" name="takeover" value="{takeover}" />
	<button type="submit" name="step" value="firstQuestion">問題1へ</button>
	<button type="submit" name="step" value="secondQuestion">問題2へ</button>
</form>

こうすることで押した方のボタンのstepに進むことができ、一つのformで完結するのでJSバリデータを動作させることができるようになります。

後書き

いかがでしたでしょうか?
応用2に関しては滅多に見ない仕様な気もするのでおまけ程度ですが、エラースクロールはUXから考えても実装しておいて損はないかなと思います。

Discussion