我正在使用反应式表单创建注册表单,客户必须在其中插入电子邮件地址。我向该控件添加了一个异步验证器,以检查所插入的电子邮件是否已在使用中。
this.form = this.formBuilder.group({
...,
emailGroup: this.formBuilder.group({
email: ['', [Validators.required, Validators.email], uniqueEmailValidator(this.registerService)],
confirmEmail: ['', [Validators.required]]
}, { validator: emailMatcher }),
...
});
我的html看起来像这样:
<div class="col-sm-6">
<div class="form-group">
<label for="reg-email">E-mailadres</label>
<input class="form-control" type="text" id="reg-email" formControlName="email" [ngClass]="{'is-invalid': form.get('emailGroup.email').errors && (form.get('emailGroup.email').touched || isSubmitted)}">
<div class="invalid-feedback">
<div *ngIf="form.get('emailGroup.email').errors?.required || form.get('emailGroup.email').errors?.email">
Please insert a valid email
</div>
<div *ngIf="form.get('emailGroup.email').errors?.uniqueEmail">
This email is already in use
</div>
</div>
</div>
</div>
最初我的异步验证器如下所示:
export function uniqueEmailValidator(registerService: RegisterService): AsyncValidatorFn {
return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
return registerService.getCustomersByEmail(c.value).pipe(
map(customers => {
return customers && customers.length > 0 ? { 'uniqueEmail': true } : null;
})
);
}
}
到目前为止一切正常。当我插入现有电子邮件时,会收到错误消息“此电子邮件已被使用”。
我注意到此异步验证器是针对每个插入的字符执行的,出于性能原因,我想避免这种情况。我决定添加一个500毫秒的计时器,并且仅在500毫秒没有活动时才执行异步验证。这将我的异步验证器更改为:
export function uniqueEmailValidator(registerService: RegisterService): AsyncValidatorFn {
return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
return timer(500).pipe(
map(x => {
return registerService.getCustomersByEmail(c.value).pipe(
map(customers => {
return customers && customers.length > 0 ? { 'uniqueEmail': true } : null;
})
);
})
);
};
}
验证器正确完成工作,并且在异步验证后,电子邮件控件被标记为无效。问题是我的html不再显示错误消息“此电子邮件已在使用中”。错误代码“ uniqueEmail”未添加到控件的错误对象中。
有人可以阐明这一点吗? 预先感谢。
答案 0 :(得分:1)
我需要完全相同的东西。所以我做的没什么不同。我创建了一个异步验证方法,该方法会在发生错误的情况下返回验证错误的保证。因此,此方法将对服务器的呼叫延迟500毫秒,并且如果在延迟期间发生任何更改,它将取消前一个超时并开始新的超时。因此,如果用户正在键入,则最终只会在服务器上发送一个呼叫。在下面看看。
声明这两个变量
validationDelay: any;
validateUniqueEmail: any;
定义以下异步验证方法。记住,我使用实例var是因为我不能在promise中使用this
上下文。所以不要感到困惑。
validateEmail( c: FormControl): Promise<{[key: string]: any}> {
const instance = this;
return new Promise(resolve => {
if (instance.validationDelay) {
clearTimeout(instance.validationDelay);
}
instance.validationDelay = setTimeout(() => {
instance.registerService.getCustomersByEmail(c.value)
.subscribe((customers) => {
if (customers && customers.length > 0) {
resolve({
uniqueEmail: true
});
} else {
resolve(null);
}
}, (err) => {
resolve(null);
});
}, 500);
});
}
现在使用此异步方法。通过以下方式初始化
ngOnInit(): void {
this.validateUniqueEmail = (control: FormControl) => {
return this.validateEmail(control);
};
}
在您的validateUniqueEmail
中使用此FormControl
email: ['', [Validators.required, Validators.email], this.validateUniqueEmail]