フォーム検証により、ユーザがフォームを正しい形式で入力し、送信されたデータがアプリケーションで正しく機能するかを確認できます。この記事では、フォーム検証に関する基本概念と例を紹介します。このチュートリアル以外の詳細については、制約検証ガイドを参照してください。
前提知識: | コンピュータリテラシー、適度な HTML、 CSS、 JavaScript の理解。 |
---|---|
目的: | フォーム検証とは何か、なぜ重要なのか、どのように実装するのかを理解すること。 |
フォーム検証とは何か
有名なサイトの登録フォームに行ってみると、指定された形式でデータを入力していない場合に、次のようなメッセージが表示されるでしょう。
- 「このフィールドは必須です」 (このフィールドが空欄にできない場合)
- 「電話番号は XXX-XXXX の形式で入力してください」 (3桁の番号の後にダッシュがあり、その後に4桁の番号で入力が必要な場合)
- 「有効なメールアドレスを入力してください」 (入力が "somebody@example.com" の形ではない場合)
- 「パスワードは8文字から30文字の間で、1文字以上の大文字、記号、数字を含む必要があります。」
これはフォーム検証と呼ばれます。データを入力するとき、Web アプリケーションはそのデータが正しいかどうかをチェックします。正しければ、アプリケーションはサーバにデータを送信し、(ふつうは) データベースに保存します。正しくなければ、何を修正する必要があるかを説明するメッセージを表示します。フォーム検証は様々な方法で実装することができます。
私たちはできるだけ簡単にフォームを埋めてもらいたいわけですが、なぜフォームを検証する必要があるのでしょうか?理由は主に三つあります。
- 正しいデータを正しい形式で入力してほしい — ユーザのデータが誤った形式で格納されたり、ユーザが正しい情報を入力しなかったり、省略したりすると、アプリケーションが正しく動作しないからです。
- ユーザのアカウントを保護したい — ユーザに安全なパスワードを入力させることで、アカウント情報を保護しやすくなります。
- 自分たちを守りたい — 悪意のあるユーザが保護のないフォームを悪用して、そのフォームを一部に持つアプリケーションに危害を加える方法がたくさんあります。(Web サイトセキュリティを参照してください)。
警告: クライアントからサーバに渡されたデータを決して信頼しないでください。フォームが正しく検証され、不正な入力が防止されている場合でも、悪意のあるユーザがネットワークリクエストを変更する可能性があります。
様々な種類のフォーム検証
Webで見かけるフォーム検証には二つの種類があります。
- クライアント側検証は、データがサーバへ送信される前にブラウザ内で行われる検証です。これはすぐに反応を返せるので、サーバ側の検証よりもユーザに親切です。これはさらに分類できます。
- JavaScript 検証は JavaScript を使ってコーディングされるものです。これは完全にカスタマイズ可能です。
- 内蔵フォーム検証は、 HTML5 のフォーム検証機能を使用します。これは一般に JavaScript を必要としません。内蔵フォーム検証はパフォーマンスは良いのですが、 JavaScript ほどカスタマイズすることはできません。
- サーバ側検証は、データが送信された後に、サーバ側で行われる検証です。サーバ側のコードは、データベースにデータを保存する前の検証に使用されます。データの検証に失敗すると、クライアントに応答を送り、ユーザに何が間違っているかを伝えます。サーバ側検証は、フォーム全体が送信されるまでエラーが表示できないので、クライアント側の検証ほどユーザに親切ではありません。しかし、サーバ側検証は不正なデータに対するアプリケーションの最終防衛線です。主要なサーバ側フレームワークはデータを検証や無害化 (安全化) する機能を持っています。
現実には、開発者はクライアント側検証とサーバ側検証を組み合わせて使う傾向があります。
内蔵フォーム検証の利用
HTML5 の機能のひとつに、スクリプトに頼ることなくほとんどのユーザデータを検証できる機能があります。これはフォーム関連要素の検証関連属性を使用すれば、値を入力する必要があるかどうか、データの最短と最長の長さ、数値であるかどうか、メールアドレスかどうかなどや、パターンに一致するかどうかなどの規則を指定することができます。入力されたデータがすべて規則に従っていれば妥当とみなされ、そうでなければ不正とみなされます。
要素が妥当な場合は、次のようになります。
- 要素が CSS の
:valid
疑似クラスに一致します。これにより、妥当な要素に特定のスタイルを適用することができます。 - ユーザがデータを送信しようとすると、ブラウザは止めるものが他になければ(JavaScript など)、フォームを送信します。
要素が不正なときは、次のようになります。
- 要素が CSS の
:invalid
疑似クラスに一致します。これにより、不正な要素に特定のスタイルを適用することができます。 - ユーザがデータを送信しようとすると、ブラウザはフォームをブロックしてエラーメッセージを表示します。
入力要素の制約の検証 ― 簡単なものから
この節では、 <input>
要素を検証するために使用することができる幾つかの異なる HTML5 の機能を見てみます。
簡単な例から始めましょう。 ― 好きな果物をバナナかサクランボから選べる入力欄があるとします。単純なテキストの <input>
とそれに合わせたラベル、送信の <button>
から成ります。ソースコードは GitHub の fruit-start.html で、ライブサンプルは次の通りです。
Hidden code
<form> <label for="choose">Would you prefer a banana or cherry?</label> <input id="choose" name="i_like"> <button>Submit</button> </form>
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; }
始めるにあたって、ハードディスク内の新しいディレクトリに fruit-start.html
のコピーを作成してください。
required 属性
required
属性は、使うのがもっとも簡単な HTML5 の検証機能です。 ― 入力欄を必須にしたい場合は、この属性を使用して要素をマークすることができます。この属性が設定されていると、入力欄が空欄の(入力欄は不正だと扱われる)場合はフォームが送信されません(そして、エラーメッセージが表示されるでしょう)。
以下のように、 required
属性を入力欄に追加しましょう。
<form> <label for="choose">Would you prefer a banana or cherry?</label> <input id="choose" name="i_like" required> <button>Submit</button> </form>
このサンプルファイルの中に含まれている CSS も書いておきましょう。
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; }
これで、入力欄が不正な時、明るい赤の破線の境界線が表示され、妥当な場合はもっと細い黒の境界線が表示されます。以下の例で新しい動作を確認しましょう。
正規表現での検証
もう一つとてもよく使われる機能は pattern
属性で、値として正規表現を取ります。正規表現(regex)はテキスト文字列の中の文字の組み合わせに一致させるために使うことができ、フォームの検証には理想的です(JavaScript と同様に様々な利用ができます)。正規表現はとても複雑であり、この記事では包括的な説明をしようとはしていません。
以下のものはどのように動作するかを基本的な考えを示す例です。
a
— a の1文字に一致する(b や aa などではない)。abc
—a
と、その次のb
と、その次のc
に一致する。a*
— 0文字以上の a に一致する(+
は1文字以上の文字に一致する)。[^a]
— a ではない1文字に一致する。a|b
— a または b の1文字に一致する。[abc]
— a、 b、 c のうち1文字に一致する。[^abc]
— a、 b、 c ではない1文字に一致する。[a-z]
— 小文字のみの a–z のいずれかの文字に一致します(大文字と小文字を使うには[A-Za-z]
、 大文字のみであれば[A-Z]
)。a.c
— a と、その次の任意の1文字と、その次の c に一致する。a{5}
— 5文字の a に一致する。a{5,7}
— 5文字から7文字の a に一致するが、それより大きくても小さくても一致しない。
次のように、数字やその他の文字もこの表現の中に入れることができます。
[ -]
— 1文字の空白又はダッシュに一致する。[0-9]
— 0から9の任意の数字に一致する。
これらを望みに合わせて本当にあらゆる方法で、さまざまな部品を次々と組み合わせて指定することができます。
[Ll].*k
— 大文字または小文字の L 1文字と、その次に任意の文字が0文字以上と、その次に小文字の k が1文字続くもの。[A-Z][A-Za-z' -]+
— 大文字1文字と、その次に大文字、小文字、ダッシュ、アポストロフィ、空白のいずれかが1文字以上続くもの。これは英語圏の国で都市や町の名前を検証するのに使うことができ、大文字1文字で始まる必要がありますが、それ以外の文字は含みません。例えばイギリスでは、 Manchester, Ashton-under-lyne, Bishop's Stortford などが一致します。[0-9]{3}[ -][0-9]{3}[ -][0-9]{4}
― アメリカの国内電話番号に単純に一致するものです。3桁の数字、その次に空白又はダッシュ1文字、その次に3桁の数字、その次に空白又はダッシュ1文字、その次に4桁の数字が続くものです。実際には一部の人は地域コードを括弧の中に書くので、もっと複雑にしなければならないでしょうが、単純なデモとして動作します。
とにかく、例を実装しましょう。 ― 次のように、 pattern
属性を HTML に追加しましょう。
<form> <label for="choose">Would you prefer a banana or a cherry?</label> <input id="choose" name="i_like" required pattern="banana|cherry"> <button>Submit</button> </form>
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; }
この例では、 <input>
要素は "banana" 又は "cherry" という2つの文字列値のうち1つを受け付けます。
この時点で、 pattern
属性の中の値を以前に見たいくつかの例と同じ値に変更してみて、入力欄が有効になるように入力する値がどのように影響するかを確認してください。自分で考えた値も書いてみて、どのようになるか確認しましょう。果物に関する値を可能にすれば、例分かりやすくなります。
メモ: <input>
要素の型によっては、検証のために pattern
属性が必要ないことがあります。例えば email
型を指定すると、入力された文字列を、妥当な形式のメールアドレス(または、 multiple
属性がある場合はコンマで区切られたメールアドレスのリスト)であることを確認する正規表現で検証します。他の例として、 url
型の入力欄は自動的に正しい形式の URL を要求します。
メモ: <textarea>
要素は pattern
属性に対応していません。
入力欄の長さの制約
<input>
または <textarea>
によって作成されたすべてのテキストフィールドはminlength
と maxlength
の属性を使ってサイズを制限できます。
値が minlength
値より短いか、maxlength
値より長い場合、フィールドは無効です。ブラウザでは、ユーザがテキストフィールドに予想以上に長い値を入力できないことがよくありますが、このきめ細かいコントロールを使用できるようにすると便利です。
数値入力欄(つまり <input type="number">
)では、 min
及び max
属性も制約の検証を行います。入力欄の値が min
属性よりも小さかったり、 max
属性よりも大きかったりすると、入力欄は無効になります。
他の例を見てみましょう。 fruit-start.html ファイルの新しいコピーを作成してください。
では、 <body>
要素の中身を削除して、以下のように置き換えてください。
<form> <div> <label for="choose">Would you prefer a banana or a cherry?</label> <input id="choose" name="i_like" required minlength="6" maxlength="6"> </div> <div> <label for="number">How many would you like?</label> <input type="number" id="number" name="amount" value="1" min="1" max="10"> </div> <div> <button>Submit</button> </div> </form>
- ここで、
text
入力欄にminlength
とmaxlength
を6に設定したのが分かるでしょう。 banana 及び cherry と同じ長さです。これ以上少ない文字を入力すると無効と表示され、多くのブラウザではそれ以上の文字を入力することはできません。 number
入力欄にはmin
を1に、max
を10に設定しました。 — この範囲外の数値は無効と表示され、値の増加・減少の矢印も、この範囲外に値を動かすことはできないでしょう。
input:invalid { border: 2px dashed red; } input:valid { border: 2px solid black; } div { margin-bottom: 10px; }
例をライブで実行してみましょう。
メモ: <input type="number">
(及び range
のような他の型)は step
属性を取ることもでき、入力コントロール(数値の増加・減少ボタンなど)を使用するときに上げ下げすることができる値の刻みを設定することができます。
サンプル全体
HTML の内蔵検証機能の使い方を示す例の全体を示します。
<form> <p> <fieldset> <legend>Title<abbr title="この入力欄は必須です">*</abbr></legend> <input type="radio" required name="title" id="r1" value="Mr"><label for="r1">Mr.</label> <input type="radio" required name="title" id="r2" value="Ms"><label for="r2">Ms.</label> </fieldset> </p> <p> <label for="n1">How old are you?</label> <!-- pattern 属性は number 型の入力欄を実装していないものの、 pattern 属性には対応しているブラウザ向けの代替策として動作できます。 なお、 pattern 属性に対応しているブラウザでは、 number 型の入力欄 で使用すると暗黙に失敗します。 ここでは代替策としての使い方のみです。 --> <input type="number" min="12" max="120" step="1" id="n1" name="age" pattern="\d+"> </p> <p> <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory">*</abbr></label> <input type="text" id="t1" name="fruit" list="l1" required pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range"> <datalist id="l1"> <option>Banana</option> <option>Cherry</option> <option>Apple</option> <option>Strawberry</option> <option>Lemon</option> <option>Orange</option> </datalist> </p> <p> <label for="t2">What's your e-mail?</label> <input type="email" id="t2" name="email"> </p> <p> <label for="t3">Leave a short message</label> <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea> </p> <p> <button>Submit</button> </p> </form>
body { font: 1em sans-serif; padding: 0; margin : 0; } form { max-width: 200px; margin: 0; padding: 0 5px; } p > label { display: block; } input[type=text], input[type=email], input[type=number], textarea, fieldset { /* WebKit ベースのブラウザでフォーム関連要素に 正しくスタイルを設定するために必要 */ -webkit-appearance: none; width : 100%; border: 1px solid #333; margin: 0; font-family: inherit; font-size: 90%; -moz-box-sizing: border-box; box-sizing: border-box; } input:invalid { box-shadow: 0 0 5px 1px red; } input:focus:invalid { outline: none; }
入力値を制限するために使用できる属性とそれらをサポートする input タイプの完全なリストについては、検証関連属性を参照してください。
独自のエラーメッセージ
上記の例で見てきたように、ユーザが不正なフォームを送信しようとするたびにブラウザはエラーメッセージを表示します。このメッセージを表示する方法は、ブラウザにより異なります。
これらの自動のメッセージには、2つの欠点があります。
- CSS でメッセージの表示方法を変更するための標準的な方法がありません。
- メッセージはブラウザのロケールに依存しており、ある言語のページでエラーメッセージが別の言語で表示されることがあります。
ブラウザ | 表示 |
---|---|
Firefox 17 (Windows 7) | ![]() |
Chrome 22 (Windows 7) | ![]() |
Opera 12.10 (Mac OSX) | ![]() |
これらのメッセージの外見やテキストを変更するには、 JavaScript を使用しなければなりません。 HTML や CSS だけで変更する方法はありません。
HTML5 では、フォーム要素の状態を確認したりカスタマイズしたりするための制約検証 API を提供します。特に、エラーメッセージのテキストを変更できます。簡単な例を見てみましょう:
<form> <label for="mail">I would like you to provide me an e-mail</label> <input type="email" id="mail" name="mail"> <button>Submit</button> </form>
JavaScript で setCustomValidity()
メソッドを呼び出します。
var email = document.getElementById("mail"); email.addEventListener("input", function (event) { if (email.validity.typeMismatch) { email.setCustomValidity("I expect an e-mail, darling!"); } else { email.setCustomValidity(""); } });
JavaScript を使用したフォーム検証
内蔵のエラーメッセージを見かけを制御したい場合や、HTML5 のフォーム検証に対応していないブラウザに対処したい場合は、 JavaScript を使用する必要があります。
HTML5 の制約検証 API
制約検証 API に対応するブラウザは増えてきており、当てにできるようになってきました。この API は各フォーム要素で使用できる一連のメソッドやプロパティで構成されています。
- HTMLButtonElement
- HTMLFieldSetElement
- HTMLInputElement
- HTMLOutputElement
- HTMLSelectElement
- HTMLTextAreaElement
制約検証 API のプロパティ
プロパティ | 説明 |
---|---|
validationMessage |
コントロールが合格していない制約検証(もしあれば)を説明するローカライズ済みのメッセージです。またはコントロールが制約の検証の対象ではない場合(willValidate が false )または要素の値が制約に合格している場合は空文字列です。 |
validity |
要素の有効性状態を記述する |
willValidate |
フォームが送信されるときに要素が検証される場合に true を返します。そうでない場合は false を返します。 |
制約検証 API のメソッド
メソッド | 説明 |
---|---|
checkValidity() |
要素の値で妥当性の問題がない場合に true を返します。そうでない場合は false を返します。要素が不正である場合、このメソッドは要素で invalid イベントを発生させます。 |
HTMLFormElement.reportValidity() |
この要素の子コントロールが検証の制約を満足するのであれば true を返します。 false が返された場合、取り消し可能な invalid イベントがすべての無効な子に対して発行され、検証の問題がユーザに報告されます。 |
setCustomValidity(message) |
要素に独自のエラーメッセージを追加します。独自のエラーメッセージを設定すると、要素が不正であるとみなされる場合に指定したエラーが表示されます。これにより JavaScript で、標準の制約検証 API で提供されるもの以外の検証不合格状態を作り出すことができます。ユーザに問題を報告する際に、メッセージが表示されます。 引数が空文字列である場合は、独自のエラーがクリアされます。 |
古いブラウザ向けには、制約検証 API に対応していないことを補うための Hyperform などのポリフィルを使用できます。すでに JavaScript を使用していますので、ポリフィルを使用することがWebサイトやWebアプリケーションの設計や実装での追加の負担にはなりません。
制約検証 API の使用例
独自のエラーメッセージを作成するために API を使用する方法を見ていきましょう。始めに、HTML です。
<form novalidate> <p> <label for="mail"> <span>Please enter an email address:</span> <input type="email" id="mail" name="mail"> <span class="error" aria-live="polite"></span> </label> </p> <button>Submit</button> </form>
このサンプルフォームでは、ブラウザの自動検証を無効にするために novalidate
属性を使用しています。これで、検証を制御するためにスクリプトを使用できます。ただし、これは制約検証 API の対応や CSS の疑似クラス :valid
, :invalid
, :in-range
, :out-of-range
の適用を無効にするわけではありません。つまり、データを送信する前にブラウザが自動的なフォームの妥当性確認を行わないとしても、あなた自身で確認を行って、フォームの状態に応じたスタイル設定ができます。
aria-live
属性は、スクリーンリーダーのような支援技術を使用している人々を含む皆に、独自のエラーメッセージを提示するようにします。
CSS
この CSS はフォームへのスタイル設定と、エラー出力をより目立つようにします。
/* これはサンプルの見栄えをよくするスタイルです */ body { font: 1em sans-serif; padding: 0; margin : 0; } form { max-width: 200px; } p * { display: block; } input[type=email]{ -webkit-appearance: none; width: 100%; border: 1px solid #333; margin: 0; font-family: inherit; font-size: 90%; -moz-box-sizing: border-box; box-sizing: border-box; } /* これは不正なフィールド向けのスタイルです */ input:invalid{ border-color: #900; background-color: #FDD; } input:focus:invalid { outline: none; } /* これはエラーメッセージ向けのスタイルです */ .error { width : 100%; padding: 0; font-size: 80%; color: white; background-color: #900; border-radius: 0 0 5px 5px; -moz-box-sizing: border-box; box-sizing: border-box; } .error.active { padding: 0.3em; }
JavaScript
以下の JavaScript コードは独自のエラー検証を制御します。
// DOM ノードの選択法はたくさんあります。ここではフォーム自体、メールアドレス // 入力ボックス、そしてエラーメッセージを配置する span 要素を取得しています。 var form = document.getElementsByTagName('form')[0]; var email = document.getElementById('mail'); var error = document.querySelector('.error'); email.addEventListener("input", function (event) { // ユーザが何かを入力するたびに、メールアドレスのフィールドが妥当かを // 確認します。 if (email.validity.valid) { // エラーメッセージを表示している場合に、フィールドが妥当になれば // エラーメッセージを取り除きます。 error.innerHTML = ""; // メッセージの内容物をリセットします error.className = "error"; // メッセージの表示状態をリセットします } }, false); form.addEventListener("submit", function (event) { // ユーザがデータを送信しようとするたびに、メールアドレスの // フィールドが妥当かをチェックします。 if (!email.validity.valid) { // フィールドが妥当ではない場合、独自のエラーメッセージを // 表示します。 error.innerHTML = "I expect an e-mail, darling!"; error.className = "error active"; // また、イベントをキャンセルしてフォームの送信を止めます。 event.preventDefault(); } }, false);
こちらが実際の結果です。
制約検証 API はフォーム検証を制御するための強力なツールであり、HTML および CSS のみで検証を行うよりもはるかにユーザインターフェイスをコントロールできます。
組み込み API を使用しないフォーム検証
古いブラウザやカスタムウィジェットにおいて、制約検証 API を使用できない (または使用したくない)ことがあるでしょう。このような場合でも、フォームを検証するために JavaScript が使用できます。フォームを検証には、実際のデータの検証よりもユーザインターフェイスの疑問が多くなります。
フォームを検証するために、あなたはいくつかの疑問を考えなければなりません。
- どのような検証を実施するべきか
- どのようにデータを検証するかを決めなければなりません。文字列演算、型変換、正規表現など。これはあなた次第です。フォームのデータは常にテキストであり、スクリプトには常に文字列として渡されることを忘れないようにしてください。
- フォームが妥当でない場合に何をするべきか
- これは明らかにユーザインターフェイスの問題です。フォームがどのように動作するかを決めなければなりません。どのような場合でもフォームのデータを送信しますか?エラー状態の入力欄を強調しますか?エラーメッセージを表示しますか?
- ユーザが不正なデータを修正することをどのように支援できるか
- ユーザの不満を軽減するためには、ユーザに入力内容の修正を案内するために、できるだけ多くの役立つ情報を提供することがとても重要です。明確なエラーメッセージはもちろん、ユーザが何を求められているか理解できるように前向きの提案をするべきです。フォーム検証のユーザインターフェイスの要件について深く知りたいのであれば、ぜひ読むべきである有用な記事があります。
- SmashingMagazine: Form-Field Validation: The Errors-Only Approach
- SmashingMagazine: Web Form Validation: Best Practices and Tutorials
- Six Revision: Best Practices for Hints and Validation in Web Forms
- A List Apart: Inline Validation in Web Forms
制約検証 API を使用しない例
これまでのことを説明するため、古いブラウザでも動作するように前出のサンプルを作り直してみましょう。
<form> <p> <label for="mail"> <span>Please enter an email address:</span> <input type="text" class="mail" id="mail" name="mail"> <span class="error" aria-live="polite"></span> </label> <p> <!-- 一部の古いブラウザでは button 要素で、 type 属性に明示的に submit を設定する必要があります。 --> <button type="submit">Submit</button> </form>
ご覧の通り、 HTML はほとんど同じであり、 HTML5 の部分を取り除いただけです。ARIA は特に HTML5 との関係はない独立した仕様ですので、ここでは残されています。
CSS
同様に、CSS も大きく変更する必要はありません。:invalid
疑似クラスから実クラスへの変更と、Internet Explorer 6 で動作しない属性セレクターの使用を避けただけです。
/* これはサンプルの見栄えをよくするスタイルです */ body { font: 1em sans-serif; padding: 0; margin : 0; } form { max-width: 200px; } p * { display: block; } input.mail { -webkit-appearance: none; width: 100%; border: 1px solid #333; margin: 0; font-family: inherit; font-size: 90%; -moz-box-sizing: border-box; box-sizing: border-box; } /* これは不正なフィールド向けのスタイルです */ input.invalid{ border-color: #900; background-color: #FDD; } input:focus.invalid { outline: none; } /* これはエラーメッセージ向けのスタイルです */ .error { width : 100%; padding: 0; font-size: 80%; color: white; background-color: #900; border-radius: 0 0 5px 5px; -moz-box-sizing: border-box; box-sizing: border-box; } .error.active { padding: 0.3em; }
JavaScript
JavaScript コードでは大きな変更があり、多くの面倒な作業が必要です。
// 古いブラウザで DOM ノードを選択する方法は少ない var form = document.getElementsByTagName('form')[0]; var email = document.getElementById('mail'); // 以下は DOM 内で次の兄弟要素にたどり着くための技です。 // これは容易に無限ループになることがあるため、危険です。 // 新しいブラウザでは、element.nextElementSibling を使用しましょう。 var error = email; while ((error = error.nextSibling).nodeType != 1); // HTML5 仕様書より var emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; // 多くの古いブラウザは addEventListener メソッドをサポートしていません。 // 以下はこれを扱うためのシンプルな方法です。なお唯一の方法ではありません。 function addEvent(element, event, callback) { var previousEventCallBack = element["on"+event]; element["on"+event] = function (e) { var output = callback(e); // `false` を返すコールバックはコールバックチェーンを止めて、 // イベントコールバックの実行を中断します。 if (output === false) return false; if (typeof previousEventCallBack === 'function') { output = previousEventCallBack(e); if(output === false) return false; } } }; // ここから検証制約の再構築ができます。 // CSS の疑似クラスに頼ることはできないため、メールアドレスフィールドで // valid/invalid クラスを明示的に設定しなければなりません。 addEvent(window, "load", function () { // ここで、フィールドが空かを確認しています (フィールドは必須入力ではありません) // 空でなければ、内容部が適切な電子メールアドレスかを確認します。 var test = email.value.length === 0 || emailRegExp.test(email.value); email.className = test ? "valid" : "invalid"; }); // ユーザがフィールドに入力したときに、何をするかを定義します。 addEvent(email, "keyup", function () { var test = email.value.length === 0 || emailRegExp.test(email.value); if (test) { email.className = "valid"; error.innerHTML = ""; error.className = "error"; } else { email.className = "invalid"; } }); // ユーザがデータを送信しようとしたときに何をするかを定義します。 addEvent(form, "submit", function () { var test = email.value.length === 0 || emailRegExp.test(email.value); if (!test) { email.className = "invalid"; error.innerHTML = "I expect an e-mail, darling!"; error.className = "error active"; // 一部の古いブラウザは event.reventDefault() メソッドをサポートしていません。 return false; } else { email.className = "valid"; error.innerHTML = ""; error.className = "error"; } });
結果は以下のようになります。
ご覧の通り、自分でで検証システムを構築するのは大変なことではありません。難しいのはクロスプラットフォームで、かつ作成するであろうあらゆるフォームで使用できる汎用的なものにすることです。フォーム検証を行うために利用できる、多くのライブラリがあります。使用するのをためらうべきではありません。いくつか例を挙げます。
- 単独のライブラリ
- jQuery プラグイン
リモート検証
場合によっては、リモートで検証を実行することが有用かもしれません。この種の検証は、ユーザが入力したデータをアプリケーションのサーバ側で保存している追加データに結び付ける際に必要になります。この利用例としては、登録フォームでユーザ名を尋ねるときです。重複を避けるためには、ユーザにデータを送信させてから、エラーを伴ったフォームを送り返すよりも、ユーザ名が利用できるかをチェックするために AJAX リクエストを実行する方がスマートです。
このような検証を実施するには、いくつか注意すべきことがあります。
- API や一部のデータを広く公開することになります。微妙なデータでないことを確認してください。
- ネットワークの遅延があるので、検証は非同期で行うことになります。検証が正しく行われなくてもユーザはブロックされないので、正しいことを確認するために UI でいくらかの作業が必要になります。
まとめ
フォーム検証に複雑な JavaScript は必要ありませんが、ユーザについて慎重に検討する必要があります。ユーザが提供するデータを修正するのを手助けすることを忘れないでください。そのためには、次のことを確認してください。
- 明確なエラーメッセージを表示してください。
- 入力形式については寛容になってください。
- どこでエラーが発生しているかを正確に示してください(特に大きなフォームで)。