JavaScriptのクラスを使ったフォームバリデーションの実装方法

JavaScriptのクラスを使ったフォームバリデーションは、現代のウェブ開発において非常に重要です。フォームバリデーションは、ユーザーが入力したデータの正確性と一貫性を保証するために必要不可欠なプロセスです。適切に実装されたバリデーションは、入力エラーを減少させ、ユーザーエクスペリエンスを向上させるだけでなく、データベースに保存されるデータの品質を保つ役割も果たします。

本記事では、JavaScriptのクラス構文を利用してフォームバリデーションを実装する方法を解説します。クラスを使用することで、バリデーションロジックを効率的に管理し、再利用可能なコードを作成することが可能になります。また、カスタムバリデーションルールの追加やバリデーション結果の表示方法についても詳しく説明します。これにより、より堅牢でメンテナンス性の高いフォームバリデーションを実現できるでしょう。

目次

フォームバリデーションの基礎

フォームバリデーションは、ユーザーが入力したデータの正確性と一貫性を確保するための重要なプロセスです。これにより、誤ったデータがサーバーに送信されるのを防ぎ、ユーザーエクスペリエンスを向上させることができます。

フォームバリデーションの目的

フォームバリデーションの主な目的は以下の通りです。

  • データの正確性:ユーザーが入力したデータが正しい形式であることを確認します。
  • セキュリティの向上:悪意のある入力やスクリプトインジェクションを防ぎます。
  • ユーザーエクスペリエンスの向上:即時にフィードバックを提供し、ユーザーがエラーを修正できるようにします。

クライアントサイドとサーバーサイドのバリデーション

  • クライアントサイドバリデーション:ユーザーのブラウザ上で行われ、即時フィードバックを提供します。JavaScriptを使用して実装され、ネットワークトラフィックを減少させます。
  • サーバーサイドバリデーション:サーバー上で行われ、クライアントサイドバリデーションの欠点を補完します。信頼性が高く、全てのデータが確実にチェックされます。

フォームバリデーションは、ユーザーが入力フォームを送信する前にデータの正確性を確認し、エラーを即座にフィードバックすることで、ユーザーの混乱を防ぎます。次のセクションでは、JavaScriptのクラスを使用してバリデーションロジックを実装する方法を学びます。

JavaScriptクラスの概要

JavaScriptのクラスは、オブジェクト指向プログラミングの概念を取り入れた構文で、コードの再利用性と保守性を高めることができます。クラスを使用することで、関連するデータとメソッドを一つのオブジェクトにまとめることができます。

JavaScriptクラスの基本構文

JavaScriptでクラスを定義するための基本的な構文は次の通りです:

class MyClass {
  constructor(property) {
    this.property = property;
  }

  myMethod() {
    console.log(this.property);
  }
}

const instance = new MyClass('Hello');
instance.myMethod(); // 出力: Hello

コンストラクタ

クラスのインスタンスが生成されるときに呼び出される特殊なメソッドです。初期化処理やプロパティの設定を行います。

メソッド

クラス内で定義された関数で、インスタンスの操作やデータ処理を行います。上記の例では myMethod がメソッドにあたります。

クラスの利点

  • カプセル化:データとメソッドを一つのオブジェクトにまとめることで、コードの整理がしやすくなります。
  • 再利用性:一度定義したクラスを他のプロジェクトや部分で簡単に再利用できます。
  • 保守性:変更が必要な場合、クラスの定義部分を修正するだけで済むため、保守が容易です。

次のセクションでは、実際にJavaScriptクラスを使ってフォームバリデーションクラスを作成する方法を説明します。これにより、フォームのバリデーションロジックを効率的に管理できるようになります。

基本的なフォームバリデーションクラスの作成

JavaScriptのクラスを使用して、シンプルなフォームバリデーションクラスを作成する方法をステップバイステップで説明します。このクラスは、フォームの入力値を検証し、エラーを管理する役割を果たします。

ステップ1: クラスの定義

まず、基本的なフォームバリデーションクラスを定義します。このクラスには、バリデーションの対象となるフォーム要素とエラーメッセージを保持するプロパティを含めます。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }
}

ステップ2: バリデーションメソッドの追加

次に、フォームの各入力フィールドを検証するメソッドを追加します。ここでは、例として必須フィールドのチェックメソッドを実装します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }
}

ステップ3: バリデーションの実行

複数のフィールドを検証するためのメソッドを追加し、全体のバリデーションを実行します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('name', 'Name');
    this.validateRequired('email', 'Email');
    // 他のフィールドも追加可能
    return Object.keys(this.errors).length === 0;
  }
}

ステップ4: バリデーションの実行とエラーメッセージの表示

フォームの送信時にバリデーションを実行し、エラーメッセージを表示するための処理を追加します。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    console.log(validator.errors);
  }
});

この基本的なクラスを拡張することで、複雑なバリデーションロジックも効率的に管理することができます。次のセクションでは、クラスメソッドを使用して入力値を検証する具体的な例を紹介します。

クラスメソッドによる入力値の検証

フォームバリデーションクラスを使って、様々な入力値を検証する方法を具体的な例を通じて説明します。これにより、フォームの各フィールドが正しい形式で入力されているかを確認できます。

ステップ1: メソッドの追加

まず、特定のバリデーションルールを実装するためのメソッドをクラスに追加します。例として、メールアドレスの形式を検証するメソッドを追加します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('name', 'Name');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    // 他のフィールドも追加可能
    return Object.keys(this.errors).length === 0;
  }
}

ステップ2: 複数のバリデーションメソッドの統合

上記のクラスにさらにバリデーションメソッドを追加し、必要に応じて複数のフィールドを検証できるようにします。例として、パスワードの強度を検証するメソッドを追加します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validatePassword(field, fieldName) {
    const value = this.form[field].value;
    if (value.length < 8) {
      this.errors[field] = `${fieldName} must be at least 8 characters long`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('name', 'Name');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    this.validateRequired('password', 'Password');
    this.validatePassword('password', 'Password');
    // 他のフィールドも追加可能
    return Object.keys(this.errors).length === 0;
  }
}

ステップ3: 実装と動作確認

上記のクラスを使用して、フォームの送信時に複数のフィールドを検証します。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    console.log(validator.errors);
  }
});

このようにして、クラスメソッドを利用して各フィールドの入力値を検証することができます。次のセクションでは、特定の要件に基づいたカスタムバリデーションルールの追加方法を解説します。

カスタムバリデーションルールの実装

特定のプロジェクト要件に基づいたカスタムバリデーションルールを実装する方法を説明します。これにより、標準的なバリデーション以外にも、独自のルールを追加することができます。

ステップ1: カスタムバリデーションメソッドの追加

まず、独自のバリデーションルールを実装するためのメソッドをクラスに追加します。例として、電話番号の形式を検証するカスタムバリデーションメソッドを追加します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validatePassword(field, fieldName) {
    const value = this.form[field].value;
    if (value.length < 8) {
      this.errors[field] = `${fieldName} must be at least 8 characters long`;
    } else {
      delete this.errors[field];
    }
  }

  validatePhoneNumber(field, fieldName) {
    const value = this.form[field].value;
    const phonePattern = /^\d{10}$/;
    if (!phonePattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid 10-digit phone number`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('name', 'Name');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    this.validateRequired('password', 'Password');
    this.validatePassword('password', 'Password');
    this.validateRequired('phone', 'Phone Number');
    this.validatePhoneNumber('phone', 'Phone Number');
    // 他のフィールドも追加可能
    return Object.keys(this.errors).length === 0;
  }
}

ステップ2: カスタムバリデーションの実行

カスタムバリデーションメソッドを含めた全体のバリデーションを実行し、エラーメッセージを表示する処理を行います。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    console.log(validator.errors);
    // 例えばエラーメッセージをUIに表示する
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

ステップ3: フロントエンドでのエラーメッセージ表示

エラーメッセージをUIに表示するために、HTML内にエラー表示用の要素を追加します。

<form id="myForm">
  <label for="name">Name</label>
  <input type="text" id="name" name="name">
  <div id="name-error" class="error-message"></div>

  <label for="email">Email</label>
  <input type="text" id="email" name="email">
  <div id="email-error" class="error-message"></div>

  <label for="password">Password</label>
  <input type="password" id="password" name="password">
  <div id="password-error" class="error-message"></div>

  <label for="phone">Phone Number</label>
  <input type="text" id="phone" name="phone">
  <div id="phone-error" class="error-message"></div>

  <button type="submit">Submit</button>
</form>

このようにして、特定のプロジェクト要件に合わせたカスタムバリデーションルールを実装することができます。次のセクションでは、バリデーション結果をユーザーに分かりやすく表示する方法を詳しく説明します。

バリデーション結果の表示

フォームバリデーションの結果をユーザーに分かりやすく表示する方法を説明します。これにより、ユーザーはどのフィールドにエラーがあり、どのように修正すれば良いかを簡単に理解できます。

ステップ1: エラーメッセージの表示領域の準備

まず、エラーメッセージを表示するためのHTML要素を各フィールドの近くに配置します。これにより、エラーが発生したフィールドに対応するメッセージが表示されます。

<form id="myForm">
  <label for="name">Name</label>
  <input type="text" id="name" name="name">
  <div id="name-error" class="error-message"></div>

  <label for="email">Email</label>
  <input type="text" id="email" name="email">
  <div id="email-error" class="error-message"></div>

  <label for="password">Password</label>
  <input type="password" id="password" name="password">
  <div id="password-error" class="error-message"></div>

  <label for="phone">Phone Number</label>
  <input type="text" id="phone" name="phone">
  <div id="phone-error" class="error-message"></div>

  <button type="submit">Submit</button>
</form>

ステップ2: CSSによるエラーメッセージのスタイリング

エラーメッセージを見やすくするために、CSSを使ってスタイリングします。

.error-message {
  color: red;
  font-size: 0.9em;
  margin-top: 5px;
}

ステップ3: JavaScriptでエラーメッセージを表示

バリデーションエラーが発生した場合、対応するエラーメッセージを表示するためのJavaScriptコードを実装します。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

ステップ4: エラーメッセージのクリア

フォームの再送信時に、以前のエラーメッセージをクリアするための処理を追加します。これにより、ユーザーがエラーを修正した際に、古いエラーメッセージが残らないようにします。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  // 以前のエラーメッセージをクリア
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

これで、フォームの各フィールドに対してバリデーション結果をわかりやすく表示することができます。次のセクションでは、既存のクラスに新しい機能を追加してバリデーションを強化する方法を紹介します。

フォームバリデーションクラスの拡張

既存のフォームバリデーションクラスに新しい機能を追加して、バリデーションを強化する方法を説明します。これにより、より複雑なバリデーション要件にも対応できるようになります。

ステップ1: 新しいバリデーションルールの追加

例えば、パスワードに大文字、小文字、数字、特殊文字を含むことを要求するルールを追加します。

class FormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validatePassword(field, fieldName) {
    const value = this.form[field].value;
    const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
    if (!passwordPattern.test(value)) {
      this.errors[field] = `${fieldName} must be at least 8 characters long and include uppercase, lowercase, number, and special character`;
    } else {
      delete this.errors[field];
    }
  }

  validatePhoneNumber(field, fieldName) {
    const value = this.form[field].value;
    const phonePattern = /^\d{10}$/;
    if (!phonePattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid 10-digit phone number`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('name', 'Name');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    this.validateRequired('password', 'Password');
    this.validatePassword('password', 'Password');
    this.validateRequired('phone', 'Phone Number');
    this.validatePhoneNumber('phone', 'Phone Number');
    return Object.keys(this.errors).length === 0;
  }
}

ステップ2: 新しいバリデーションの実行

追加したバリデーションルールを実行し、エラーメッセージを表示する処理を行います。

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new FormValidator(form);

  // 以前のエラーメッセージをクリア
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // フォームの送信処理
  } else {
    // エラーメッセージの表示処理
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

ステップ3: リアルタイムバリデーションの追加

入力中にリアルタイムでバリデーションを行うことで、ユーザーに即時フィードバックを提供します。

const form = document.getElementById('myForm');
const validator = new FormValidator(form);

form.addEventListener('input', function(event) {
  const field = event.target.name;
  const errorElement = document.getElementById(`${field}-error`);

  if (field === 'name') {
    validator.validateRequired(field, 'Name');
  } else if (field === 'email') {
    validator.validateEmail(field, 'Email');
  } else if (field === 'password') {
    validator.validatePassword(field, 'Password');
  } else if (field === 'phone') {
    validator.validatePhoneNumber(field, 'Phone Number');
  }

  if (validator.errors[field]) {
    errorElement.textContent = validator.errors[field];
  } else {
    errorElement.textContent = '';
  }
});

このように、フォームバリデーションクラスを拡張して、複雑なバリデーション要件にも対応できるようにすることができます。次のセクションでは、一般的なバリデーションエラーの原因とその解決方法について説明します。

バリデーションエラーのトラブルシューティング

フォームバリデーションで発生する一般的なエラーの原因と、その解決方法を説明します。これにより、よりスムーズにバリデーションを実装できるようになります。

ステップ1: エラーメッセージが表示されない

エラーメッセージが正しく表示されない場合の原因と対策を説明します。

原因1: HTMLのIDとJavaScriptのフィールド名の不一致

フィールド名とエラーメッセージを表示する要素のIDが一致していない場合、エラーメッセージが表示されません。

<!-- 間違った例 -->
<input type="text" id="name" name="name">
<div id="name-errorr" class="error-message"></div> <!-- タイポ -->
// JavaScript側での対応
const errorElement = document.getElementById('name-error'); // 正しいIDを指定

原因2: バリデーションメソッドの呼び出し順序の問題

バリデーションメソッドが正しい順序で呼び出されていない場合、エラーメッセージが表示されないことがあります。

validate() {
  this.validateRequired('name', 'Name');
  this.validateEmail('email', 'Email');
  this.validatePassword('password', 'Password');
  this.validatePhoneNumber('phone', 'Phone Number');
  return Object.keys(this.errors).length === 0;
}

ステップ2: バリデーションロジックが正しく動作しない

バリデーションロジックが期待通りに動作しない場合の原因と対策を説明します。

原因1: 正規表現の誤り

正規表現が正しく記述されていない場合、バリデーションが正しく行われません。

validateEmail(field, fieldName) {
  const value = this.form[field].value;
  const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 正しいパターン
  if (!emailPattern.test(value)) {
    this.errors[field] = `${fieldName} must be a valid email address`;
  } else {
    delete this.errors[field];
  }
}

原因2: 必須フィールドのチェック漏れ

必須フィールドのチェックが抜けていると、空のフィールドが許容されてしまいます。

validate() {
  this.validateRequired('name', 'Name');
  this.validateRequired('email', 'Email');
  this.validateEmail('email', 'Email');
  this.validateRequired('password', 'Password');
  this.validatePassword('password', 'Password');
  this.validateRequired('phone', 'Phone Number');
  this.validatePhoneNumber('phone', 'Phone Number');
  return Object.keys(this.errors).length === 0;
}

ステップ3: ユーザーに対するエラーメッセージが分かりにくい

エラーメッセージがユーザーにとって分かりにくい場合、より具体的でわかりやすいメッセージに修正します。

validateRequired(field, fieldName) {
  const value = this.form[field].value;
  if (!value) {
    this.errors[field] = `Please enter your ${fieldName}.`;
  } else {
    delete this.errors[field];
  }
}

ステップ4: リアルタイムバリデーションが遅延する

入力中のリアルタイムバリデーションが遅延する場合の対策を説明します。

原因1: バリデーションの過剰な実行

入力イベントごとにバリデーションが頻繁に実行されると、パフォーマンスに影響を与えることがあります。

form.addEventListener('input', _.debounce(function(event) {
  const field = event.target.name;
  const errorElement = document.getElementById(`${field}-error`);

  if (field === 'name') {
    validator.validateRequired(field, 'Name');
  } else if (field === 'email') {
    validator.validateEmail(field, 'Email');
  } else if (field === 'password') {
    validator.validatePassword(field, 'Password');
  } else if (field === 'phone') {
    validator.validatePhoneNumber(field, 'Phone Number');
  }

  if (validator.errors[field]) {
    errorElement.textContent = validator.errors[field];
  } else {
    errorElement.textContent = '';
  }
}, 300)); // lodashのdebounce関数を使用して遅延を防ぐ

これらのトラブルシューティングのポイントを押さえることで、フォームバリデーションの実装をよりスムーズに進めることができます。次のセクションでは、学んだ知識を基にした実践的な演習問題を提示します。

実践演習

ここでは、これまで学んだ知識を実際に使ってフォームバリデーションを実装する演習問題を紹介します。これにより、理解を深め、実践的なスキルを身につけることができます。

演習問題1: 住所フォームのバリデーション

ユーザーが入力する住所フォームのバリデーションを実装します。フォームには「郵便番号」「都道府県」「市区町村」「番地」のフィールドがあります。各フィールドに対するバリデーションルールを設定し、入力データの正確性をチェックします。

<form id="addressForm">
  <label for="zip">Postal Code</label>
  <input type="text" id="zip" name="zip">
  <div id="zip-error" class="error-message"></div>

  <label for="prefecture">Prefecture</label>
  <input type="text" id="prefecture" name="prefecture">
  <div id="prefecture-error" class="error-message"></div>

  <label for="city">City</label>
  <input type="text" id="city" name="city">
  <div id="city-error" class="error-message"></div>

  <label for="address">Address</label>
  <input type="text" id="address" name="address">
  <div id="address-error" class="error-message"></div>

  <button type="submit">Submit</button>
</form>
class AddressFormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validatePostalCode(field, fieldName) {
    const value = this.form[field].value;
    const postalCodePattern = /^\d{3}-\d{4}$/;
    if (!postalCodePattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid postal code (e.g., 123-4567)`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('zip', 'Postal Code');
    this.validatePostalCode('zip', 'Postal Code');
    this.validateRequired('prefecture', 'Prefecture');
    this.validateRequired('city', 'City');
    this.validateRequired('address', 'Address');
    return Object.keys(this.errors).length === 0;
  }
}

document.getElementById('addressForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new AddressFormValidator(form);

  // Clear previous error messages
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // Form submission logic
    console.log('Form submitted successfully!');
  } else {
    // Display error messages
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

演習問題2: カスタムバリデーションの追加

以下の要件を満たすフォームを作成し、バリデーションを実装します。

  • 「ユーザー名」: 必須、英数字のみ
  • 「生年月日」: 必須、有効な日付形式
  • 「メールアドレス」: 必須、有効なメールアドレス形式
<form id="customForm">
  <label for="username">Username</label>
  <input type="text" id="username" name="username">
  <div id="username-error" class="error-message"></div>

  <label for="birthdate">Birthdate</label>
  <input type="text" id="birthdate" name="birthdate" placeholder="YYYY-MM-DD">
  <div id="birthdate-error" class="error-message"></div>

  <label for="email">Email</label>
  <input type="text" id="email" name="email">
  <div id="email-error" class="error-message"></div>

  <button type="submit">Submit</button>
</form>
class CustomFormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateAlphanumeric(field, fieldName) {
    const value = this.form[field].value;
    const alphaNumPattern = /^[a-zA-Z0-9]+$/;
    if (!alphaNumPattern.test(value)) {
      this.errors[field] = `${fieldName} must be alphanumeric`;
    } else {
      delete this.errors[field];
    }
  }

  validateDate(field, fieldName) {
    const value = this.form[field].value;
    const datePattern = /^\d{4}-\d{2}-\d{2}$/;
    if (!datePattern.test(value) || isNaN(new Date(value).getTime())) {
      this.errors[field] = `${fieldName} must be a valid date (YYYY-MM-DD)`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('username', 'Username');
    this.validateAlphanumeric('username', 'Username');
    this.validateRequired('birthdate', 'Birthdate');
    this.validateDate('birthdate', 'Birthdate');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    return Object.keys(this.errors).length === 0;
  }
}

document.getElementById('customForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new CustomFormValidator(form);

  // Clear previous error messages
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // Form submission logic
    console.log('Form submitted successfully!');
  } else {
    // Display error messages
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

これらの演習を通じて、JavaScriptのクラスを使ったフォームバリデーションの実装方法を実際に体験し、理解を深めてください。次のセクションでは、複数のフォーム要素をバリデートする応用例を紹介します。

応用例

ここでは、複数のフォーム要素をバリデートする応用例を紹介します。これにより、より複雑なフォームのバリデーションにも対応できるようになります。

応用例1: 会員登録フォームのバリデーション

以下の要件を満たす会員登録フォームを作成し、バリデーションを実装します。

  • 「ユーザー名」: 必須、英数字のみ
  • 「パスワード」: 必須、8文字以上、大文字・小文字・数字・特殊文字を含む
  • 「確認パスワード」: 必須、パスワードと一致すること
  • 「メールアドレス」: 必須、有効なメールアドレス形式
  • 「電話番号」: 必須、有効な10桁の数字
<form id="registerForm">
  <label for="username">Username</label>
  <input type="text" id="username" name="username">
  <div id="username-error" class="error-message"></div>

  <label for="password">Password</label>
  <input type="password" id="password" name="password">
  <div id="password-error" class="error-message"></div>

  <label for="confirmPassword">Confirm Password</label>
  <input type="password" id="confirmPassword" name="confirmPassword">
  <div id="confirmPassword-error" class="error-message"></div>

  <label for="email">Email</label>
  <input type="text" id="email" name="email">
  <div id="email-error" class="error-message"></div>

  <label for="phone">Phone Number</label>
  <input type="text" id="phone" name="phone">
  <div id="phone-error" class="error-message"></div>

  <button type="submit">Register</button>
</form>
class RegisterFormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateAlphanumeric(field, fieldName) {
    const value = this.form[field].value;
    const alphaNumPattern = /^[a-zA-Z0-9]+$/;
    if (!alphaNumPattern.test(value)) {
      this.errors[field] = `${fieldName} must be alphanumeric`;
    } else {
      delete this.errors[field];
    }
  }

  validatePassword(field, fieldName) {
    const value = this.form[field].value;
    const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
    if (!passwordPattern.test(value)) {
      this.errors[field] = `${fieldName} must be at least 8 characters long and include uppercase, lowercase, number, and special character`;
    } else {
      delete this.errors[field];
    }
  }

  validateConfirmPassword(field, fieldName) {
    const password = this.form['password'].value;
    const confirmPassword = this.form[field].value;
    if (password !== confirmPassword) {
      this.errors[field] = `${fieldName} must match the password`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validatePhoneNumber(field, fieldName) {
    const value = this.form[field].value;
    const phonePattern = /^\d{10}$/;
    if (!phonePattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid 10-digit phone number`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('username', 'Username');
    this.validateAlphanumeric('username', 'Username');
    this.validateRequired('password', 'Password');
    this.validatePassword('password', 'Password');
    this.validateRequired('confirmPassword', 'Confirm Password');
    this.validateConfirmPassword('confirmPassword', 'Confirm Password');
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    this.validateRequired('phone', 'Phone Number');
    this.validatePhoneNumber('phone', 'Phone Number');
    return Object.keys(this.errors).length === 0;
  }
}

document.getElementById('registerForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new RegisterFormValidator(form);

  // Clear previous error messages
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // Form submission logic
    console.log('Registration successful!');
  } else {
    // Display error messages
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

応用例2: ログインフォームのバリデーション

以下の要件を満たすログインフォームを作成し、バリデーションを実装します。

  • 「メールアドレス」: 必須、有効なメールアドレス形式
  • 「パスワード」: 必須
<form id="loginForm">
  <label for="email">Email</label>
  <input type="text" id="email" name="email">
  <div id="email-error" class="error-message"></div>

  <label for="password">Password</label>
  <input type="password" id="password" name="password">
  <div id="password-error" class="error-message"></div>

  <button type="submit">Login</button>
</form>
class LoginFormValidator {
  constructor(form) {
    this.form = form;
    this.errors = {};
  }

  validateRequired(field, fieldName) {
    const value = this.form[field].value;
    if (!value) {
      this.errors[field] = `${fieldName} is required`;
    } else {
      delete this.errors[field];
    }
  }

  validateEmail(field, fieldName) {
    const value = this.form[field].value;
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailPattern.test(value)) {
      this.errors[field] = `${fieldName} must be a valid email address`;
    } else {
      delete this.errors[field];
    }
  }

  validate() {
    this.validateRequired('email', 'Email');
    this.validateEmail('email', 'Email');
    this.validateRequired('password', 'Password');
    return Object.keys(this.errors).length === 0;
  }
}

document.getElementById('loginForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const validator = new LoginFormValidator(form);

  // Clear previous error messages
  const errorMessages = form.querySelectorAll('.error-message');
  errorMessages.forEach(function(message) {
    message.textContent = '';
  });

  if (validator.validate()) {
    // Form submission logic
    console.log('Login successful!');
  } else {
    // Display error messages
    for (const field in validator.errors) {
      const errorElement = document.getElementById(`${field}-error`);
      if (errorElement) {
        errorElement.textContent = validator.errors[field];
      }
    }
  }
});

これらの応用例を通じて、より複雑なフォームのバリデーションを実装する方法を学びましょう。次のセクションでは、記事全体のまとめとして、重要なポイントを振り返ります。

まとめ

本記事では、JavaScriptのクラスを使ったフォームバリデーションの実装方法について解説しました。基本的なクラスの定義から始まり、様々なバリデーションルールの実装方法や、カスタムバリデーションの追加方法について学びました。また、バリデーション結果をユーザーにわかりやすく表示する方法や、複数のフォーム要素をバリデートする応用例についても紹介しました。

フォームバリデーションは、ユーザーが入力するデータの正確性と一貫性を確保するために重要な役割を果たします。クラスを使用することで、バリデーションロジックを効率的に管理し、再利用可能で保守性の高いコードを作成することができます。

今後、さらに複雑なバリデーション要件に対応する際にも、本記事で学んだ基本的なアプローチを活用し、より堅牢でユーザーフレンドリーなフォームバリデーションを実装してください。

コメント

コメントする

目次