JavaScript | 1 日 120 分 × 7 日アプリ学習:フォームバリデーションアプリ

JavaScript
スポンサーリンク

6日目のゴールと今日のテーマ

6日目は「バリデーションの“質”と“柔軟性”をさらに高める日」です。
昨日までで、あなたはすでに

  • 設定オブジェクトによるフィールド管理
  • 共通ハンドラ(input / blur)
  • バリデーション関数の外部化
  • エラー表示のテンプレート化

といった“中級フォーム設計の基礎”を身につけました。

今日はここからさらに一歩進めて、

  • 複数ルールを組み合わせたバリデーション(ルール配列)
  • エラーの優先順位を設定で管理する
  • フィールド追加に完全対応する設計
  • UX をさらに自然にする(即時・遅延・条件付き)

という「実務レベルのフォーム設計」に近づけていきます。


バリデーションルールを「配列」で管理する

なぜ配列化が必要なのか

昨日までの validate 関数はこうでした。

function validatePassword(value) {
  if (!value) return "必須です";
  if (value.length < 8) return "8文字以上にしてください";
  if (!/[A-Za-z]/.test(value)) return "英字を含めてください";
  return "";
}
JavaScript

これは悪くありませんが、フィールドが増えると

  • ルールが増える
  • 条件が複雑になる
  • validate 関数が巨大化する

という問題が起きます。

そこで、ルールを配列で管理し、順番にチェックする方式に進化させます。

ルール配列の例(パスワード)

const passwordRules = [
  {
    message: "パスワードを入力してください。",
    validate: (value) => value.length > 0,
  },
  {
    message: "8文字以上にしてください。",
    validate: (value) => value.length >= 8,
  },
  {
    message: "英字を1文字以上含めてください。",
    validate: (value) => /[A-Za-z]/.test(value),
  },
  {
    message: "数字を1文字以上含めてください。",
    validate: (value) => /\d/.test(value),
  },
];
JavaScript

ここでの重要ポイントは、

  • ルールを「データ」として扱えるようになる
  • ルールの追加・削除が簡単になる
  • validate 関数がスリムになる

という設計の柔軟性です。

ルール配列を使った validate 関数

function validateByRules(value, rules) {
  for (const rule of rules) {
    if (!rule.validate(value)) {
      return rule.message;
    }
  }
  return "";
}
JavaScript

パスワードの validate はこう書けます。

function validatePassword(value) {
  return validateByRules(value, passwordRules);
}
JavaScript

これで、ルールを増やしても validatePassword は変わりません。


メールも同じ方式にする

メールのルール配列

const emailRules = [
  {
    message: "メールアドレスを入力してください。",
    validate: (value) => value.length > 0,
  },
  {
    message: "メールアドレスの形式が正しくありません。",
    validate: (value) => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value),
  },
];
JavaScript

validateEmail はこうなります。

function validateEmail(value) {
  return validateByRules(value, emailRules);
}
JavaScript

ここでの深掘りポイントは、

  • メールのルールを増やしたいときは emailRules に追加するだけ
  • validateEmail の中身は一切変えなくてよい

という「保守性の高さ」です。


設定オブジェクトに「ルール配列」を組み込む

fields をルール配列対応にする

const fields = {
  email: {
    selector: "#email",
    errorSelector: "#email-error",
    rules: emailRules,
  },
  password: {
    selector: "#password",
    errorSelector: "#password-error",
    rules: passwordRules,
  },
};
JavaScript

validateField をこう書き換えます。

function validateField(name, value) {
  const rules = fields[name].rules;
  return validateByRules(value, rules);
}
JavaScript

ここでの重要ポイントは、

  • validateField が完全に汎用化された
  • フィールド追加時に validate 関数を作らなくてもよい
  • ルール配列を設定するだけでバリデーションが動く

という「設計の完成度」です。


UX をさらに自然にする:即時・遅延・条件付きバリデーション

即時バリデーション(リアルタイム)

すでに touched のフィールドは input のたびにチェックしています。

これは「即時バリデーション」です。

メリット

  • すぐにフィードバックが返る
  • ユーザーが迷わない

デメリット

  • 入力途中で赤くなるとストレス

遅延バリデーション(debounce)

昨日導入した「300ms 待ってからチェック」は遅延バリデーションです。

メリット

  • 入力途中のストレスが減る
  • UX が自然になる

条件付きバリデーション

例えばパスワード確認欄は、

  • password が空のときはチェックしない
  • password が touched のときだけチェックする

という条件付きにできます。

const passwordConfirmRules = [
  {
    message: "確認用パスワードを入力してください。",
    validate: (value) => value.length > 0,
  },
  {
    message: "パスワードが一致しません。",
    validate: (value, values) => value === values.password,
  },
];
JavaScript

validateByRules を拡張して values を渡せるようにします。

function validateByRules(value, rules, values) {
  for (const rule of rules) {
    if (!rule.validate(value, values)) {
      return rule.message;
    }
  }
  return "";
}
JavaScript

ここでの深掘りポイントは、

  • ルール配列が「他のフィールドの値」を参照できるようになった
  • パスワード確認のような複合バリデーションが簡単に書ける

という点です。


submit 制御を「ルール配列ベース」で再構築する

submit 時の全体チェック

formEl.addEventListener("submit", (event) => {
  event.preventDefault();

  for (const name in fields) {
    state.touched[name] = true;
    state.errors[name] = validateByRules(
      state.values[name],
      fields[name].rules,
      state.values
    );
  }

  if (hasFormError()) {
    state.errors.form = "入力内容を確認してください。";
    render();
    return;
  }

  state.errors.form = "";
  state.isSubmitting = true;
  render();

  setTimeout(() => {
    state.isSubmitting = false;
    state.errors.form = "送信成功!(ダミー)";
    render();
  }, 800);
});
JavaScript

ここでの重要ポイントは、

  • submit 時のチェックがルール配列に完全依存する
  • フィールド追加時に submit のコードを変更しなくてよい
  • フォーム全体の状態を一元管理できる

という「大規模フォームにも耐える設計」になっていることです。


6日目のまとめと、明日へのつなぎ

今日あなたが身につけたのは、まさに「実務レベルのフォーム設計」です。

  • バリデーションルールを配列化して柔軟性を高めた
  • validateByRules によってバリデーションを完全に汎用化した
  • 設定オブジェクトにルールを組み込み、フィールド追加に強くした
  • 即時・遅延・条件付きバリデーションを理解した
  • submit 制御をルール配列ベースで再構築した

明日(7日目)はいよいよ総仕上げとして、

  • フォーム全体を“コンポーネント化”する設計
  • 大規模フォームに耐える構造(セクション・ステップ)
  • アクセシビリティ(A11y)を意識したバリデーション
  • 実務で使えるバリデーションパターン集

など、「中級から上級へ進むための橋渡し」を行います。

今日のコードを触りながら、

  • ルールを1つ追加するとどう動くか
  • フィールドを1つ追加するとどこを変えればよいか
  • 設計がどれだけ壊れにくいか

を確認してみると、設計力が一気に伸びます。

タイトルとURLをコピーしました