始めに
タイトルの出オチ記事です。
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を用いて検証していると思っていたのですが、処理が開始されたタイミングの状態しか持っていないことを把握していませんでした。
バックエンドと比べて、フロントは難しいです…。