uhyohyo.net

JavaScript初級者から中級者になろう

十二章第二回 フォーム

このページの最終更新日:

HTML5になって、フォームが大きく進化しました。そこで、それをJavaScriptで扱う方法を紹介します。どのように進化したかについてはぜひ調べてみましょう。

妥当性チェック

HTML5のフォームには、妥当性validity)という概念があります。これは要するに、入力内容が正しいかどうかということです。

そこでまず、あるフォームの妥当性をチェックするということをやってみましょう。

もちろん、各コントロール(inputなどの入力欄)にそれぞれ妥当性があります。フォームが妥当であるということは、そのフォームに属する全てのコントロールが妥当である(入力内容が正しい)ということを表します。

フォームは、その入力内容が全て正しいときのみ送信が可能になります。つまり、フォームが妥当であるとは、そのフォームが送信可能な状態であるということを表します。

フォームの妥当性チェック

あるフォームが妥当な状態であるかどうかをJavaScriptで調べるのは簡単です。form要素のノードがあったら、そのノードのcheckValidityというメソッド(引数なし)を呼び出すと、true(妥当である)かfalse(妥当でない)の真偽値を返します。

また、reportValidityというメソッド(引数なし)があります。これも返り値はcheckValidityと同様で、妥当ならばtrue、妥当でなければfalseです。ただし、reportValidityの場合、妥当でない場合はユーザーにエラーが表示されます

checkValidityとreportValidityのサンプルを用意しました。サンプルの動作やサンプルのソースコードも合わせて確認してください。

なお、このサンプルのソースコード中ではonclick属性中のスクリプトでthis.form.checkValidity()などとしています。

実は、イベントハンドラの中ではthisevent.currentTargetと同じもの、つまりそのイベントハンドラが登録されている要素を指すことになっています。よって、今回の場合thisはボタンのinput要素です。そして、input要素をはじめとするフォームコントロールはformというプロパティを持っており、これはそのコントロールが属するform要素です(なければnull)。

このサンプルではcheckValidityとreportValidityは同じ値を返すものの、後者はユーザーにエラーを表示するという点で動作が異なることが分かると思います。また、reportValidityにより表示されるエラーは「送信」ボタンを押したときのエラーと同じはずです。reportValidityはユーザーが慣れ親しんだUI(ブラウザに備え付けのUI)でエラーを表示することができるため、独自のエラー表示を作るよりも分かりやすいと考えられます。

コントロールの妥当性チェック

form要素だけでなく、input要素・select要素・button要素・fieldset要素などなどの各コントロールにも、妥当性チェックをするためのメソッドがあります。実は、こちらのほうがいろいろあって機能が豊富です。

まず、form要素と同様にcheckValidityreportValidityがあります。これは、フォーム全体ではなく、その要素が妥当であるかどうかを判定できます。

ここで、これを利用したサンプルを用意してみました。「郵便番号」に7桁の数字を入力するとそれに合わせた(今回は適当ですが)住所を表示するというサンプルです。

サンプル2

このサンプルでは、郵便番号のinput要素にoninputという属性があるのが分かります。onで始まるのはイベント属性なので、今回の場合inputというイベントです。これは、ユーザーによってinput要素の入力内容が変化した場合に起こるイベントで、今回のように、フォームの入力を監視する際に役立ちます。

入力内容の変化を検知できるイベントとしてHTML4時代にはchangeというイベントもありましたが、これはinput要素からフォーカスが外れないと発生しないなど使いにくいものでした。一方のinputイベントは入力内容が変化した瞬間に(厳密には少し違いますが)発生するため便利です。このHTML5で新しく導入されたinputイベントを利用する機会のほうが多いでしょう。

inputイベントの処理は下で定義された関数inpで行っています。先に説明した通り、引数は当該input要素です。

関数inp内ではいろいろやっていますが、結局何をやっているかというと、「郵便番号」が正しく入力されていれば「住所」のところに住所を自動で入力するというだけです。

「郵便番号が正しく入力されている」とは、ここでは7桁の数字が入力されているということです。それをJavaScriptでどう表現するかというと、

input.checkValidity()

だけです。つまり、このinputが妥当であるかどうか調べているだけです。

それでは「7桁の数字」の部分はどう表現しているかというと、これはHTML5の範疇ですが、実はinput要素のpattern属性に書いてあります。

pattern="\d{7}"

これは見慣れた正規表現で、は「数字7桁」を表していますね。HTML5では、このように入力内容を正規表現を用いて指定できるのです。ただし、これは部分一致ではなく、全体で一致しないといけません。だから、「a1234567」のように余計な物があってはいけません。

pattern属性がある場合、この正規表現に入力内容がマッチするならば妥当であると判断されます。ですから、JavaScript側からはcheckValidity()で妥当性をチェックするだけでいいのです。

もちろん、JavaScript側で/^\d{7}$/.test(input.value)のようにして同様のチェックを行うことは可能です。しかし、HTMLにより妥当性を定義することによりブラウザのサポートを受けてより分かりやすいUIを作ることができます。例えば、サンプル2ではCSSにより入力内容が妥当でない場合はinput要素の背景色が赤くなります。

ところで、このinput要素を見るとtitle属性があります。

title="郵便番号は7桁の数字を入力して下さい。"

このように、入力内容に制限があり複雑な場合、制限はtitle属性を用いて説明するのがよいとされています。title要素の内容はエラーメッセージとして表示されます。

コントロールの妥当性に関してもっと詳細な情報を取得するために、input要素等のノードにはvalidityというプロパティがあります。これはValidityStateというオブジェクトのインスタンスです。

このオブジェクトはいくつかのプロパティを持ち、全て真偽値です。まずvalidというプロパティは、その要素が妥当であるかどうかを返します。つまり、input.checkValidity()input.validity.validは同じです。

そして、これがfalseだった場合、すなわち妥当ではないコントロールに対しては、他のプロパティが活躍します。他のプロパティは全て、妥当ではない原因を表しています。以下に列挙します。

valueMissing
required属性(入力が必須)があるのに入力されていない場合true。
typeMismatch
type="email",type="url"の場合に、正しい書式でない場合にtrue。
patternMismatch
pattern属性で指定された条件に合っていない場合true。
tooLong
maxlength属性で決められた長さより長い場合にtrue。
rangeUnderflow
数値入力コントロールで、min属性よりも低い場合true。
rangeOverflow
数値入力コントロールでmax属性よりも高い場合true。
stepMismatch
数値入力コントロールで、strep属性で指定した単位とあわない場合true。
customError
独自エラー(後述)がある場合true。

これを用いて、妥当でない場合の細かい原因をチェックできるのです。例えばさっきの郵便番号のサンプルの場合、input.validity.valueMissinginput.validity.patternMismatchのどちらかがtrueになっていることが期待されます。

そして、独自エラーというものが出てきました。これは、HTMLが持つ機能だけでは表せないような複雑な条件である場合に、JavaScript側から「妥当である」とか「妥当でない」ということを決めてやることができるのです。

そのために使うメソッドが、コントロールのノードが持つメソッドsetCustomValidityです。これは、引数を1つ持ち、それはエラーメッセージです。この関数を呼び出すとエラーメッセージが設定され、その要素は妥当ではなくなります。

一度setCustomValidityで妥当でなくしたコントロールを再び妥当な状態に戻すには、setCustomValidityの引数を空文字列("")にして呼び出します。これにより独自エラーを解除できます。

ということで、奮発してまたサンプルを用意しました。よくある感じで、パスワードを2回入力して一致しないとだめというやつです。

サンプル

今のサンプルではinputイベントのハンドラをform要素に書いています。これは、2つのコントロールで発生したinputイベントをどちらも処理するためです。

今回もCSSで妥当でないコントロールが赤くなります。試してみると、2つ目のコントロールは1つ目のコントロールと入力内容が一致するときのみ妥当になります。これはJavaScriptからsetCustomValidityで制御されていることで可能になっています。

最後に、input要素(など)が持つwillValidateプロパティを紹介します。これは真偽値で、その要素が制約バリデーション候補である(妥当か妥当でないかの判断の対象となる)かどうかです。というのも、たとえばtype属性が"hidden"とか、あるいは"button"とかの場合はユーザーが入力するものではないですから、妥当であるとか妥当でないとかいう概念が無いのです。

数値入力とステップ

数値入力のinput(type="number", type="range")には、ステップというものがあります。例えば、


<input type="number" min="0" step="10">

というinput要素では、値として0,10,20,30,40,…を入力できます。

このようなinput要素に対してはstepUp及びstepDownというメソッドが使用できます。引数は数値1つで、引数をnとすると、n段階だけ数値を上げ/下げるメソッドです。

例えば上のinputで数値が0のとき、input.stepUp(3)を実行すると30になります。30の状態からstepDown(2)を実行すると10になるでしょう。

日付入力

日付入力のinput要素の場合、入力内容は日付を表す文字列(ISO 8601形式)です。このようなinput要素から、文字列よりも扱いやすい形式で値を取得できる方法があります。

valueAsDateは、日付をDateオブジェクトで取得できるプロパティです。Dateオブジェクトはこれまで紹介していませんでしたが、昔からある組み込みオブジェクトで、日付を表すものですす。

またvalueAsNumberは、日付を1970年1月1日の0時からのミリ秒数で取得できます。