こんにちは、フロントエンドエンジニアのいなばです。
今回は、前回の記事(↓)の続きになります。 HTML5 + JavaScriptによるFormバリデーション ~マークアップ編~
目次
今回やりたいこと(前回の続き)
- 不正な入力値のとき、エラー内容をリアルタイムに表示させる
- 各項目の入力内容を見て、送信ボタンの非活性/活性を都度切り替える
前回は、HTML5から追加された、フォームのバリデーションに関する機能をおさらいしました。今回は、JavaScriptからフォームの要素にアクセスして、バリデーションの制御を行います。
不正な入力値のとき、エラー内容をリアルタイムに表示させる
まずは、やりたいことの1つ目からみていきます。
「不正な入力値のとき、エラー内容をリアルタイムに表示させる」ためには、フォームの変更を都度検知できるようにする必要がありますね。
JavaScriptでフォームの変更を検知する
JavaScriptでフォームの変更を検知するサンプルを用意してみました。
サンプルでは、form要素にchangeイベントとinputイベントの2つのイベントをつけています。
- changeイベント: チェックボックスやセレクトメニューなどの変更を検知
- inputイベント: 主にテキストフィールドに入力があった時を検知
formの子要素にいちいちイベントをつけなくても、form要素に2つのイベントをつけることで、すべての子要素の変更が取得できていますね。
この挙動が不思議に感じる方は、下記の記事が参考になると思います。
DOMイベントのキャプチャ/バブリングを整理する 〜 JSおくのほそ道 #017
JavaScriptでエラー内容を取得する
フォームの変更を検知することはできました。 次はフォームの各子要素からエラー内容を取得したいと思います。
エラーメッセージの取得
こちらが、各子要素のエラーメッセージをconsole.logで出してみたサンプルです。
サンプルでは、変更があった要素のvalidationMessageというプロパティを見ています。
このプロパティは、要素のバリデーションが通っているときは空文字列が入り、不正な入力の際はエラー文言文字列が入ります。 validationMessageは言語設定を見て言語も切り替わってくれるのですが、ブラウザごとにエラー文言が異なり、エラー文言として適切でない場合も多いので、そのまま使うケースは少ないと思います。
エラーの詳細を取得
フォーム要素に生えているvalidityというプロパティから、エラーの状態を判断することができます。
validityの構造は下記のようになっており、
interface ValidityState {
readonly badInput: boolean;
readonly customError: boolean;
readonly patternMismatch: boolean;
readonly rangeOverflow: boolean;
readonly rangeUnderflow: boolean;
readonly stepMismatch: boolean;
readonly tooLong: boolean;
readonly tooShort: boolean;
readonly typeMismatch: boolean;
readonly valid: boolean;
readonly valueMissing: boolean;
}
validityの各プロパティの内容は、それぞれの条件を満たすかどうかのフラグとなっています。
{
badInput: 不完全な値だとブラウザが判断したときtrue
customError: 独自エラーメッセージがセットされているときtrue
patternMismatch: pattern属性で指定した要件を満たさない時true
rangeOverflow: max属性で指定した最大値を超えているときtrue
rangeUnderflow: min属性で指定した最小値に満たないときtrue
stepMismatch: step属性で指定した規則に一致しない時true
tooLong: maxlength属性で指定した長さを超えているときtrue
tooShort: minlength属性で指定した長さに満たないときtrue
typeMismatch: 入力値が要件を満たさない時true(emailやurlなど)
valid: 値の妥当性にひとつでも問題があるときtrue
valueMissing: 必須なのに値がない時true
}
element.validityをconsole.logで出してみたサンプルです
独自バリデーションをJavaScriptで設定する
フォーム要素の持つsetCustomValidity関数を呼んで、独自のバリデーションをセットすることができます。
setCustomValidity関数は、引数に文字列を取ります。文字列をセットすると、先ほどのvalidationMessageに同じ文字列が渡り、validity.customErrorがtrueになります。
逆にsetCustomValidity関数に空文字列を渡して実行すると、独自バリデーションを解除したことになり、validity.customErrorがfalseに戻ります。
実際の使い方をサンプルで見てみましょう。
サンプルの「パスワード」と「新しいパスワード」inputの入力値が一致しないときに、エラー文言が表示されることが確認できたでしょうか?
ここまでやってきたことを駆使すると、やりたいことの1つめ、「不正な入力値のとき、エラー内容をリアルタイムに表示させる」は実現できそうですね。
フォームの子要素の取得
上のパスワード確認のサンプルでは、パスワードの比較のためにinput要素2つそれぞれにアクセスする必要がありました。
フォーム内のinputタグやselectタグは、下記のようにname属性でアクセス可能になっています。
- form[子要素のname属性]
- form.elements[子要素のname属性]
ただし、フォーム要素が持っているプロパティと同じkey名をname属性に使うと、もともとのプロパティを上書きして挙動がおかしくなるので注意が必要です。
name属性にprefixをつけるなどすることで、回避することをオススメします。
各項目の入力内容を見て、送信ボタンの非活性/活性を都度切り替える
長々とやってきましたが、残るは送信ボタンの制御のみです。 これはとても簡単です。
送信ボタンの非活性の制御
form要素は、checkValidityという関数を持っています。
この関数を使うことで、formのバリデーションが総合的に通っているかどうかを知ることができます。
なので、
- form.checkValidity() が
- trueなら送信ボタンからdisabled属性を削除
- falseなら送信ボタンにdisabled属性をつける
とするだけです。とても簡単ですね。
おわりに
いかがでしたか?
実際に手を動かして学ぶことが重要なので、ハンズオン用のサンプルも用意してみました。
よければフォークして、前回と今回の記事を見ながらフォームのバリデーションを実装してみてください。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。