0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Angular Material FormGroupとReactiveForms実践例|AI実務ノート 編集部

Last updated at Posted at 2026-01-03

1. 結論(この記事で得られること)

この記事を読むと、以下が手に入ります。

  • Angular Material + ReactiveForms の正しい組み合わせ方がコードレベルで分かる
  • バリデーションエラーの表示タイミング、状態管理のベストプラクティスを理解できる
  • 実務で必須の動的フォーム生成・配列操作(FormArray)・カスタムバリデーターまで網羅
  • AI(Claude / GPT)を使った爆速デバッグ・設計レビュー方法が身につく
  • テスト観点・失敗パターン集で、本番リリース前に地雷を踏まずに済む

昔の自分に教えたかった内容を、現場目線で全部詰め込みました。

2. 前提(環境・読者層)

想定読者

  • Angular の基礎(Component, Service, DI)は理解している
  • ReactiveForms を触ったことはあるが、実務レベルの設計に自信がない
  • Angular Material を導入したけど、エラーハンドリングがうまくいかない

検証環境

Angular: 17.x
Angular Material: 17.x
TypeScript: 5.x

※ Angular 14 以降なら大きな差異はありません。Standalone Component でも動作します。

3. Before:よくあるつまずきポイント

実務で何度も見てきた"あるある"を3つ挙げます。

3-1. エラーメッセージが出ない / 出続ける

// ❌ 危険な実装例
<mat-error *ngIf="form.get('email').invalid">
  メールアドレスが不正です
</mat-error>

問題点:

  • 初期表示時から赤字エラーが出る(UX最悪)
  • 「form.get('email')」 が null の場合に実行時エラーになる
  • どのバリデーションに引っかかったか分からない

私も新人時代、これでレビューで差し戻されました。

3-2. FormControl と mat-form-field の接続ミス

// ❌ formControlName を書き忘れ
<mat-form-field>
  <input matInput placeholder="メールアドレス">
</mat-form-field>

Angular Material は formControlName がないとバリデーション状態を認識しません。  
エラーが出ないのに、裏では required が効いてないという事故が起きます。

3-3. disabled 属性の罠

// ❌ これは動かない
<input matInput formControlName="name" [disabled]="true">

ReactiveForms では HTML の 「disabled」 属性は無視されます。  
正しくは 「form.get('name').disable()」 を使う必要があります。

4. After:基本的な解決パターン

4-1. 安全なエラー表示(touched 制御)

// user-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 
@Component({
  selector: 'app-user-form',
  templateUrl: './user-form.component.html',
})
export class UserFormComponent implements OnInit {
  form!: FormGroup;
 
  constructor(private fb: FormBuilder) {}
 
  ngOnInit(): void {
    this.form = this.fb.group({
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(8)]],
    });
  }
 
  // エラー取得ヘルパー(null 安全)
  getErrorMessage(controlName: string): string {
    const control = this.form.get(controlName);
    if (!control || !control.errors || !control.touched) {
      return '';
    }
 
    if (control.errors['required']) return '必須項目です';
    if (control.errors['email']) return 'メール形式が不正です';
    if (control.errors['minlength']) {
      const required = control.errors['minlength'].requiredLength;
      return `${required}文字以上で入力してください`;
    }
    return '';
  }
 
  onSubmit(): void {
    if (this.form.invalid) {
      // 全フィールドを touched にしてエラーを表示
      this.form.markAllAsTouched();
      return;
    }
    console.log(this.form.value);
  }
}
<!-- user-form.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <mat-form-field appearance="outline">
    <mat-label>メールアドレス</mat-label>
    <input matInput formControlName="email" type="email">
    <mat-error>{{ getErrorMessage('email') }}</mat-error>
  </mat-form-field>
 
  <mat-form-field appearance="outline">
    <mat-label>パスワード</mat-label>
    <input matInput formControlName="password" type="password">
    <mat-error>{{ getErrorMessage('password') }}</mat-error>
  </mat-form-field>
 
  <button mat-raised-button color="primary" type="submit">
    送信
  </button>
</form>

ポイント:

  • 「touched」 で「ユーザーが触った後だけ」エラーを出す
  • 「markAllAsTouched()」 で送信時に全エラーを表示
  • 「getErrorMessage()」 で null 安全とエラー種別を一元管理

4-2. disabled の正しい制御

ngOnInit(): void {
  this.form = this.fb.group({
    name: [{ value: '', disabled: false }, Validators.required],
    age: [{ value: null, disabled: true }], // 初期状態で無効化
  });
 
  // 動的に制御
  this.form.get('name')?.valueChanges.subscribe(value => {
    if (value === 'admin') {
      this.form.get('age')?.disable();
    } else {
      this.form.get('age')?.enable();
    }
  });
}

注意:

  • disabled なコントロールは 「form.value」 に含まれません
  • 含めたい場合は 「form.getRawValue()」 を使う
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?