サンプルコードで身につける: フォームのバリデーション — Validators
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1Validators.required — 必須入力にする
FormControl の第2引数に Validators.required を渡すと、未入力の間はそのコントロールが invalid になります。form.invalid を送信ボタンの [disabled] につなぐだけで、「入力するまで送信できない」挙動が作れます。もっとも基本で、もっとも使用頻度の高いバリデーターです。
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-name-form',
imports: [ReactiveFormsModule],
// 未入力の間は form.invalid が true なのでボタンが押せない
template:
'<form [formGroup]="form">' +
' <input formControlName="name" placeholder="名前(必須)">' +
' <button [disabled]="form.invalid">送信</button>' +
'</form>',
})
export class NameFormComponent {
form = new FormGroup({
// 第2引数にバリデーターを渡す
name: new FormControl('', Validators.required),
});
}
2Validators.email — メール形式を検証する
Validators.email を付けると、値がメールアドレスの形式かどうかを判定してくれます。形式が正しくない間は invalid になり、errors に email のエラーが入ります。注意点として、空文字はこのバリデーターではエラーにならないため、必須にしたい場合は required と組み合わせます。
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-email-form',
imports: [ReactiveFormsModule],
template:
'<form [formGroup]="form">' +
' <input formControlName="email" placeholder="メールアドレス">' +
' @if (form.get("email")?.invalid) {' +
' <p>メール形式で入力してください</p>' +
' }' +
'</form>',
})
export class EmailFormComponent {
form = new FormGroup({
// 'tanaka' は invalid、'tanaka@example.com' は valid になる
email: new FormControl('', Validators.email),
});
}
3Validators.minLength — 最低文字数を決める
Validators.minLength(8) のように数を渡すと、その文字数未満の間は invalid になります。パスワードやユーザー名など「短すぎる入力を弾きたい」項目の定番です。errors の minlength には要求文字数と実際の文字数が入るので、メッセージに埋め込むこともできます。
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-password-form',
imports: [ReactiveFormsModule],
template:
'<form [formGroup]="form">' +
' <input formControlName="password" type="password">' +
' @if (form.get("password")?.errors?.["minlength"]) {' +
' <p>パスワードは8文字以上にしてください</p>' +
' }' +
'</form>',
})
export class PasswordFormComponent {
form = new FormGroup({
// 8文字未満の間は errors に minlength が入る
password: new FormControl('', Validators.minLength(8)),
});
}
4複数のバリデーターを配列で組み合わせる
1つの項目に複数の条件を課すときは、バリデーターを配列で渡します。[Validators.required, Validators.email] なら「必須かつメール形式」で、どちらか1つでも失敗すればそのコントロールは invalid です。実務のフォームでは、ほとんどの項目がこの組み合わせ形になります。
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-signup-form',
imports: [ReactiveFormsModule],
template:
'<form [formGroup]="form">' +
' <input formControlName="email" placeholder="メール">' +
' <input formControlName="password" type="password">' +
' <button [disabled]="form.invalid">登録</button>' +
'</form>',
})
export class SignupFormComponent {
form = new FormGroup({
// 配列で渡すと「すべて満たしたときだけ valid」になる
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.minLength(8)]),
});
}
5errors と touched でエラーメッセージを出し分ける
errors にはどの検証で失敗したかが入るため、required と email で別々のメッセージを出せます。さらに touched(一度触れたか)と組み合わせて「触れたあとに無効ならエラー表示」とすると、入力前から赤いエラーが出る不自然さを防げます。実務のエラー表示は、ほぼこのパターンに落ち着きます。
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-email-errors',
imports: [ReactiveFormsModule],
// touched && invalid のときだけ、失敗した検証に応じたメッセージを出す
template:
'<form [formGroup]="form">' +
' <input formControlName="email" placeholder="メール">' +
' @if (email.touched && email.invalid) {' +
' @if (email.errors?.["required"]) { <p>メールは必須です</p> }' +
' @if (email.errors?.["email"]) { <p>メール形式で入力してください</p> }' +
' }' +
'</form>',
})
export class EmailErrorsComponent {
email = new FormControl('', [Validators.required, Validators.email]);
form = new FormGroup({ email: this.email });
}