添加计时器后 AbstractControl 不包含异步验证错误
AbstractControl doesn't contain async validation error after adding a timer
我正在创建一个带有反应式表单的注册表单,客户必须在其中插入电子邮件地址。我向此控件添加了一个异步验证器,以检查插入的电子邮件是否已在使用中。
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;
})
);
}
}
到目前为止一切正常。当我插入现有电子邮件时,我收到错误消息 'this email is already in use'。
我注意到这个异步验证器是针对每个插入的字符执行的,出于性能原因,我想避免这种情况。我决定添加一个 500 毫秒的计时器,并且仅在 500 毫秒没有 activity 时才执行异步验证。这将我的异步验证器更改为:
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 不再显示错误消息 'This email is already in use'。错误代码 'uniqueEmail' 没有添加到我的控件的错误对象中。
有人可以阐明这一点吗?
提前致谢。
我需要完全相同的东西。所以我做的有点不同。我创建了一个异步验证方法,该方法 returns 在出现错误时承诺验证错误。因此,此方法将对服务器的调用延迟 500 毫秒,如果在延迟期间有任何变化,它会取消先前的超时并启动新的超时。因此,如果用户正在输入,最终只会在服务器上发送一次调用。往下看
声明这两个变量
validationDelay: any;
validateUniqueEmail: any;
定义以下异步验证方法。请记住,我使用实例变量是因为我无法在承诺中使用 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);
};
}
在您的 FormControl
中使用此 validateUniqueEmail
email: ['', [Validators.required, Validators.email], this.validateUniqueEmail]
我正在创建一个带有反应式表单的注册表单,客户必须在其中插入电子邮件地址。我向此控件添加了一个异步验证器,以检查插入的电子邮件是否已在使用中。
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;
})
);
}
}
到目前为止一切正常。当我插入现有电子邮件时,我收到错误消息 'this email is already in use'。
我注意到这个异步验证器是针对每个插入的字符执行的,出于性能原因,我想避免这种情况。我决定添加一个 500 毫秒的计时器,并且仅在 500 毫秒没有 activity 时才执行异步验证。这将我的异步验证器更改为:
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 不再显示错误消息 'This email is already in use'。错误代码 'uniqueEmail' 没有添加到我的控件的错误对象中。
有人可以阐明这一点吗? 提前致谢。
我需要完全相同的东西。所以我做的有点不同。我创建了一个异步验证方法,该方法 returns 在出现错误时承诺验证错误。因此,此方法将对服务器的调用延迟 500 毫秒,如果在延迟期间有任何变化,它会取消先前的超时并启动新的超时。因此,如果用户正在输入,最终只会在服务器上发送一次调用。往下看
声明这两个变量
validationDelay: any;
validateUniqueEmail: any;
定义以下异步验证方法。请记住,我使用实例变量是因为我无法在承诺中使用 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);
};
}
在您的 FormControl
validateUniqueEmail
email: ['', [Validators.required, Validators.email], this.validateUniqueEmail]