以下の内容はhttps://nainaistar.hatenablog.com/entry/2025/01/20/120000より取得しました。


AngularのValidatorを変更するならupdateValueAndValidityも呼ぶ

始めに

タイトルの出オチ記事です。

Angularにて、状態によってユーザーをnameで検索したり、emailで検索するinputがありました。

emailの場合は完全一致してほしいので、入力値がemail形式であることを検証し、nameの場合は検証しないようにしたいです。

今回の記事では、処理中に状態を判断してValidatorを変更しつつ、適切な検証を行えるようにします。

環境

  • Angular
    • 18.0.4

実装

今回の例ではFormControlで実装します。

基本データバインディング

HTML

HTML側では後で定義するnameOrEmailControlとデータバインドしておきます。

<input type="email" [formControl]="nameOrEmailControl">

TypeScript

nameでも、emailでも、requiredを付与します。

public nameOrEmailControl: FormControl = new FormControl("", [
  Validators.required,
]);

状態に応じてemail検証を追加する

今回の場合、初期状態はrequiredのみ検証している状態にし、入力が走ったタイミングでemailを追加検証します。

追加する場合はaddValidatorsでもよいのですが、状態が分からなくなるのでsetValidatorsを使用します。

this.nameOrEmailControl.setValidators([
  Validators.required,
  Validators.email,
]);

Validatorsが変更されたタイミングでは検証が走らないので、意図的に検証を走らせるためにupdateValueAndValidityを呼びます。emitEventをfalseにしているのは、今回の検証時のコードではvalueChangesが走っているせいで無限ループに入ったので抑制しています。

this.nameOrEmailControl.updateValueAndValidity({ emitEvent: false });
ngOnInit() {
  this.nameOrEmailControl.valueChanges
    .subscribe((value) => {
      console.log("value:", value);
      console.log(this.nameOrEmailControl.valid);
      // 後からValidatorsを変更する場合は、updateValueAndValidityを呼ぶ必要がある
      // 初回だけTRUE, FALSEとなっている
      // 2回目以降はValidatorsが設定済みなので、TRUE, TRUEかFALSE, FALSEになる
      this.nameOrEmailControl.setValidators([
        Validators.required,
        Validators.email,
      ]);
      // FormControlの検証
      this.nameOrEmailControl.updateValueAndValidity({ emitEvent: false });

      console.log(this.nameOrEmailControl.valid);
  });
}

ソースコード

終わりに

this.nameOrEmailControl.validが最新のValidatorsを用いて検証していると思っていたのですが、処理が開始されたタイミングの状態しか持っていないことを把握していませんでした。

バックエンドと比べて、フロントは難しいです…。




以上の内容はhttps://nainaistar.hatenablog.com/entry/2025/01/20/120000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14