🔖

Angular のクロスフィールドバリデーション

2022/04/21に公開

クロスフィールドバリデータ

Angular でフォーム項目同士のバリデーションを実施するケースのバリデーション関数を、クロスフィールドバリデータといいます。

Web アプリケーションでは例えば以下のような場面で利用されるケースが多いでしょう。

  • パスワードの入力確認
  • 年月日フィールドのチェック
  • 姓名フィールドとカナフィールドの読み方一致チェック

フォーム全体へのバリデーション

フォーム全体へのバリデーションとして定義する場合は以下のような形で実装可能です。

import {
  AbstractControl,
  FormControl,
  FormGroup,
  ValidationErrors,
  ValidatorFn,
  Validators,
} from '@angular/forms';

const passwordMatchValidator_form: ValidatorFn = (
  control: AbstractControl
): ValidationErrors | null => {
  const pass1 = control.get('password');
  const pass2 = control.get('password2');

  if (pass1.value === pass2.value) {
    return null;
  } else {
    return { passwordMatch: true };
  }
};

export const makeAppForm = () => {
  return new FormGroup(
    {
      email: new FormControl('', [Validators.required, Validators.email]),
      password: new FormControl('', [Validators.required]),
      password2: new FormControl('', [Validators.required]),
    },
    { validators: [passwordMatchValidator_form] }
  );
};

FormGroup は第二引数でフォーム全体のバリデーション関数を受け取ることができます。

validator 関数の引数 control には、FormGroup 全体が渡されるため、get を利用してそれぞれの項目を取得できます。

エラー結果の取得はフォーム全体から form.errors のようにして取得する必要があり、
password2.errors のように項目からエラーの状態を検知する事ができません。

フォーム項目のバリデーターとして

フォーム項目のバリデータ関数で、クロスフィールドバリデーションを実現することもできます。

import {
  AbstractControl,
  FormControl,
  FormGroup,
  ValidationErrors,
  ValidatorFn,
  Validators,
} from '@angular/forms';

const passwordMatchValidator_input: ValidatorFn = (
  control: AbstractControl
): ValidationErrors | null => {
  if (!control.parent) {
    return { passwordMatch: true };
  }
  const pass1 = control.parent.get('password');
  const pass2 = control;

  if (pass1.value === pass2.value) {
    return null;
  } else {
    return { passwordMatch: true };
  }
};

export const makeAppForm = () => {
  return new FormGroup(
    {
      email: new FormControl('', [Validators.required, Validators.email]),
      password: new FormControl('', [Validators.required]),
      password2: new FormControl('', [
        Validators.required,
        passwordMatchValidator_input,
      ]),
    }
  );
};

この場合カスタムヴァリデータ関数は、 password2 の項目に直接渡すことができます。

注意しなければ行けないのは、 バリデータ関数の引数、control.parent は 最初 null で取得されるため、
if 分岐で 処理する必要がある、ということです。

この実装を進めた場合、エラーの状態は password2.errors のように項目から取得することができます。

参考

demo

https://stackblitz.com/edit/angular-ivy-jtjpd2?file=src%2Fapp%2Fform.ts

https://angular.jp/guide/form-validation

Discussion