需求背景
在 Angular 的表单验证方面,有的时候,我们可能需要根据后台返回的数据进行验证,比如,在提交表单之前,验证你输入的用户名是否已经存在。
此时,我们需要引入 Angular 的 AsyncValidators 来实现。
使用方法
首先,我们在接口服务文件中定义一个请求后台的方法:
in-payment.service.ts
checkIfUserNameExists(value: string) {
// 模拟请求后台的方法
// 如果用户输入了其中的名字,则弹出提示:用户名已经存在
const existingUserNames = ['Tom', 'Amy', 'Lili'];
return of(existingUserNames.includes(value)).pipe(
delay(1000)
);
}
接下来,我们创建一个专门用来做表单验证的服务文件,form-validators:
form-validators.service.ts
import { Injectable } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms';
import { map, Observable } from 'rxjs';
import { InPaymentService } from './in-payment.service';
@Injectable()
export class FormValidatorsService {
constructor() { }
isNumberValidator(service: InPaymentService): AsyncValidatorFn{
return (control: AbstractControl): Observable<ValidationErrors | null> => {
return service.checkIfUserNameExists(control.value).pipe(
// 如果已经存在这个名字,则返回 { userNameExists: true }
// 如果不存在这个名字,则返回 null
map(res => res ? { userNameExists: true } : null),
)
}
}
}
然后,在需要使用这个校验服务的组件中引入该服务,并配置异步验证器数组:
search.component.ts
initFormGroup(): void{
this.searchGroup = this.fb.group({
companyCd: '',
caseNo: ['', {
// 同步校验配置
validators: [Validators.required],
// 异步校验配置
// 这里我们传入了接口的服务 this.service
// 这样才能在表单验证的服务中使用接口服务
asyncValidators:[this.formService.isNumberValidator(this.service)],
// 默认情况下,输入框表单绑定 input 方法
// 这会导致每输入一个字符都会发送 HTTP 请求
// 我们可以通过 updateOn 属性来设置表单的触发事件
updateOn: 'blur'
}],
});
}
最后,在模板中进行配置:
search.component.html
<mat-form-field class="example-form-field form-container" appearance="fill">
<mat-label>姓名</mat-label>
<input matInput type="text" formControlName="caseNo">
<!-- 在模板中配置该校验的报错信息 -->
<mat-error *ngIf="searchGroup.get('caseNo')?.hasError('userNameExists')">名字已经存在</mat-error>
<button matSuffix mat-icon-button aria-label="Clear" (click)="clearCaseNo()">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>