目次
前置き
クライアント側での単項目チェックによく使われる「リアルタイムバリデーション」をAngularで実装するためのTIPSです。
実装手順
フォームグループを作る
FormBuilderやFormGroupを使ってコントロールをまとめる
form = this.fb.group({
username: ['', []],
email: ['', []]
});バリデーションを設定する
- 各コントロールに
Validatorsを追加 - 非同期バリデーション(サーバー照会)を使うなら
asyncValidatorsに設定
form = this.fb.group({
username: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]]
});HTMLにフォームを描く
formGroupディレクティブでフォーム全体をバインドformControlName属性で各入力とコントロールを紐づける- エラーメッセージは
control.touched && control.invalidを条件に表示
Angular 15 までの書き方
- 構文は
*ngIfを使う
<form [formGroup]="form">
<input formControlName="username">
<div *ngIf="form.get('username')?.touched && form.get('username')?.invalid">
ユーザー名が不正です
</div>
</form>Angular 17 以降の書き方
- 新しい構文ベースの制御フローが追加され、
@if/@for/@switchが使える ngIfでも書けるけど、17以降はこの構文が公式に推奨されている
<form [formGroup]="form">
<input formControlName="username">
@if (username.touched && username.invalid) {
<p class="error">ユーザー名が不正です</p>
}
</form>イメージ
ヘルパについて
Angularのフォームまわりでよく出てくる 「繰り返し書きがちな処理をまとめた補助関数」 のことをヘルパと呼びます。
バリデーションやエラーメッセージ周りは、どうしてもテンプレートに条件式が増えがちです。
そこで「処理を関数化」してまとめると効率が良くなります。
ヘルパの例
コントロール取得ヘルパ
getCtl(name: string) {
return this.form.get(name);
}→ HTMLで form.get('username') を毎回書かなくて済む
@if (getCtl('username')?.touched && getCtl('username')?.invalid) {
<p class="error">ユーザー名が不正です</p>
}エラーメッセージ生成ヘルパ
getErrorMessage(controlName: string): string | null {
const c = this.form.get(controlName);
if (!c || !c.errors) return null;
if (c.errors['required']) return '必須項目です。';
if (c.errors['minlength']) return `最低 ${c.errors['minlength'].requiredLength} 文字必要です。`;
if (c.errors['email']) return 'メール形式が不正です。';
return '入力内容を確認してください。';
}→ HTMLがスッキリ書ける
@if (username.touched && username.invalid) {
<p class="error">{{ getErrorMessage('username') }}</p>
}共通バリデータを作るヘルパ
コンポーネント外(validators/ ディレクトリなどに共通バリデーションモジュールを配置)にまとめることも多いです。
import { AbstractControl, ValidationErrors } from '@angular/forms';
export function noEmojiValidator(c: AbstractControl): ValidationErrors | null {
const regex = /[\\u{1F600}-\\u{1F64F}]/u; // 絵文字
return regex.test(c.value) ? { noEmoji: true } : null;
}→ 複数のフォームで再利用できる。
ヘルパのメリット
- テンプレートが読みやすくなる
- 同じロジックを何度も書かなくて済む
- 1入力項目に複数エラーが出たときも「最初の1つだけ表示」など、ルールを一元化できる
- プロジェクトが大きくなっても保守が楽
だいたいの場合、バリデーションを実装するときは、ヘルパもセットになるはず!
最後に
ざっくりではありますが、それなりにまとまったような気がしています。しかし、まだ慣れないなあ、Angularには。

コメント