フォームでエラーになった時にはエラーの場所までスクロールしたい

これは a-blog cms Advent Calendar 2021 13日目 の記事です。

今回はいつもWebサイトを作る中で「時間があったらやろう」と思いつつなかなかできていなかった、バリデータ付きフィールドを生成した時のお供になるような機能を書いてみました。

フォームの「内容の確認へ」ボタンを押した時に、画面外で必須項目の入力漏れがあるとWebサイトの閲覧に慣れていない場合なかなかそのエラーに気づくことができません。
そんな時に役立ちそうな、エラー文までスクロールする機能を紹介します(ちゃんと検証してないので参考程度にながめてください)。


お問い合わせの「内容を確認へ」ボタンを押しても次に進まないのは画面外でエラーが出ているから

Ver. 2.12 がもうすぐリリースされるはずなので、Ver. 2.12 環境想定で書いてます。
コピペしてみたいなという方は、最新のベータ版の「UTSUWA」だときっと簡単にお試しできます。

この記事を読むのに必要な事前知識

関連記事

書いてみたコード

UTSUWAテーマにあるコードを活用しつつ少し追記していく形で書いてみました。

スクロール処理の定義

エラーコメントが発生している一番初めの要素までスクロールする処理を定義するファイルを用意します。

/src/js/validate-scroll-to.js

import scrollToElement from 'scroll-to-element';

/**
 * エラーコメントが発生している一番初めの要素までスクロールします。
 * エラー検出イベント内で読み込んでください。
 * 引数 : formEle ... フォームタグ要素
 * 引数 : itemSelecter ... エラーメッセージが発生している要素を囲んでいる要素。
 * 引数 : errorClass ... エラーメッセージのクラス
 * 引数 : offsetNum ... スクロールのオフセット
 * 返り値 : スクロール先要素 - 一応用意したけど使ってない
 */
export default (formEle, itemSelecter, errorClass = '.validator-result-0', offsetNum = -60) => {
  const errorElements = formEle.querySelectorAll(errorClass);
  if (errorElements.length > 0) {
    const errorItem = errorElements[0].closest(itemSelecter);
    scrollToElement(errorItem, {
      offset: offsetNum,
      ease: 'in-out-quad',
      duration: 800,
    });
    return errorItem;
  }
  return false;
};

UTSUWAテーマにはいている scroll-to-element を活用しています。

お問い合わせフォームでの処理呼び出し

UTSUWAテーマ内での http://ドメイン/contact/ での利用を想定したソースコードです。

組み込みJSを読み込んでいる時の処理

投稿者以上でCMSにログインしている時は組み込みJSが読み込まれるようになっているので、組み込みJSであるACMSのイベントハンドラを使用します。 acmsValidateFailed は、フォームのsubmitボタンを押してバリデートに失敗した時に発火します。

/src/js/index.js

// 〜省略
import validateScrollTo from './validate-scroll-to';
// 〜省略

if (window.ACMS === undefined) {
// 〜省略
} else {
  // 〜省略
  // 投稿者以上でログインしている時(組み込みJS読み込み時)の処理
  ACMS.Ready(() => {
    ACMS.addListener('acmsValidateFailed', (event) => {
      const errorClass = '.validator-result-0';
      const itemSelecter = '.form-group';
      validateScrollTo(event.target, itemSelecter, errorClass);
    });
  });
}
// 〜省略

組み込みJSを読み込んでいない時の処理

UTSUWAテーマ内にあるバリデーター用のJSには既にフォームの送信ボタンが押された時の処理が記載されていましたので、そちらに追記してみました。

/src/js/lib/buildIn/validator.js

// 〜省略
import validateScrollTo from '../../validate-scroll-to';
// 〜省略

export default (elm) => {
  // 〜省略
  elm.addEventListener('submit', (e) => {
    if (!validator.all(elm)) {
      // 〜省略
      const errorClass = '.validator-result-0';
      const itemSelecter = '.form-group';
      validateScrollTo(e.target, itemSelecter, errorClass);
    }
  });
};

エントリー編集ページのエラースクロール

ついでにエントリーのカスタムフィールドでのエラースクロールもやってみました。

カスタムフィールドメーカー で入力チェック付きの項目をJavaScriptによるバリデートを使用するにチェックを入れた状態で生成した時を想定して書きました。


カスタムフィールドメーカーでJavaScriptによるバリデートを使用するにチェック

やってはみましたが、スクロール位置がズレてしまいました。なので validateScrollTo をやめて代替となるような処理をしています。発火タイミングがよくないのかうまく要素の位置情報をとれていないのか...。
また後日調べて修正するかもです。

代替処理としては、ざっくり言うと エントリー保存ボタンクリック → エラー検出 → エントリー編集ページの上の方にアラート表示 → アラート表示付近までスクロール ということをしています。

/src/js/edit.js

// import validateScrollTo from './validate-scroll-to';
import scrollToElement from 'scroll-to-element'; // 代替処理

export default () => {
  ACMS.Ready(() => {
    // 〜省略
    const entryForm = document.querySelector('.entryFormWrapper');
    if (entryForm) {
      // const itemSelecter = 'td';
      const errorClass = '.validator-result-0';
      // validateScrollTo(entryForm, itemSelecter, errorClass);
      const errorElements = entryForm.querySelectorAll(errorClass);

      // validateScrollToだとスクロール位置がズレるので代替処理を行う。
      if (errorElements.length > 0) {
        const html = '<p class="acms-admin-alert acms-admin-alert-icon acms-admin-alert-danger"><span class="acms-admin-icon acms-admin-icon-news acms-admin-alert-icon-before" aria-hidden="true"></span><button class="js-acms-alert-close acms-admin-alert-icon-after">×</button>入力に誤りがあります。項目のエラーメッセージを確認してください。</p>';
        entryForm.insertAdjacentHTML('afterbegin', html);
        scrollToElement(entryForm, {
          offset: -60,
          ease: 'in-out-quad',
          duration: 800,
        });
      }
    }
  });
};

Chromeで 動くなぁ くらいしか検証していないので、参考程度に眺めていただく分には安全に読める記事となっています。

この処理書いたことある! or やってるよ! or あのコード気になる! という方は Twitter @rachicom_sugar などから「ここはこうがいいと思う」や「この記事参考になるよ」などの温かいコメントお待ちしてます。


明日の a-blog cms Advent Calendar 2021 14日目 は、TKDさんのフォームのスパム対策についてのようです!今ホットな話題なので楽しみですね!


関連記事

ファイルを添付できるフォームハマりどころ6選

ファイルを添付できるフォームのハマりどころ6選

entry:loopの外でもエントリーのカスタムフィールドの情報を表示させる(a-blog cms Ver. 2.9)

タグ