我创建了一个自定义异步验证器,该验证器使用服务来验证服务器上的电子邮件。但是,这意味着每次输入字符都会打服务器,这是不好的。在这里,我已经遵循了几个无法继续工作的答案。
我的验证者:
import {FormControl, NG_ASYNC_VALIDATORS, Validator} from
'@angular/forms';
import { Http } from '@angular/http';
import {Directive, forwardRef} from "@angular/core";
import {ValidateEmailService} from "../services/validate-email.service";
import {UserService} from "../services/user.service";
@Directive({
selector: '[appEmailValidator]',
providers: [
{ provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => EmailValidator), multi: true }
]
})
export class EmailValidator implements Validator {
public validateEmailService: ValidateEmailService;
constructor(
private _http: Http,
private _userService: UserService
) {
this.validateEmailService = new ValidateEmailService(this._http, this._userService);
}
validate(c: FormControl) {
return new Promise(resolve => {
this.validateEmailService.validateEmail(c.value)
.subscribe((res) => {
console.log(res);
if (res.valid) {
resolve(null);
} else {
resolve({
valid: {
valid: false
}
});
}
});
})
}
}
它本身可以很好地工作,但是一旦我尝试向其添加某种形式的去抖动功能,我最终就将其破坏了。
我尝试了this question的答案,但在Type X is not assignable to type 'Observable<any>'
等方面却出现了错误。
我通过使用setTimeout
接近了,但最终所做的只是停止功能。
我的最终目标是仅在输入未更改约600 ms的情况下运行验证器,但会确定每600-2000 ms仅验证一次。
为更加清楚起见,请使用validateEmail
中的ValidateEmailService
方法:
public validateEmail(email: string) {
let validateEmail = new ValidateEmail(email);
return this._http.get(
this.getUrl(validateEmail),
this.getOptionArgs())
.map((response: Response) => Object.assign(new UserEmailVerification(), response.json().UserEmailVerification));
}
答案 0 :(得分:2)
我还没有看到作为指令实现的异步验证器,而是分配给表单控件的验证器功能。
这是我用于类似情况的示例验证器:
import { Injectable } from '@angular/core';
import { AbstractControl, AsyncValidatorFn } from '@angular/forms';
import { Observable, timer, of } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { MembershipsService } from '@app/memberships/memberships.service';
@Injectable()
export class MembershipsValidators {
constructor (
private membershipsService: MembershipsService,
) {}
checkMembershipExists(email?: string): AsyncValidatorFn {
return (control: AbstractControl): Observable<{ [key: string]: any } | null> => {
if (control.value === null || control.value.length === 0) {
return of(null);
}
else if (email && email === control.value) {
return of(null);
}
else {
return timer(500).pipe(
switchMap(() => {
return this.membershipsService.lookupMember(control.value).pipe(
map(member => {
if (!member) {
return { noMembership: { value: control.value } };
}
return null;
})
);
})
);
}
};
}
}
它被导入并应用于表单控件,例如:
this.form = this.formBuilder.group({
memberEmail: new FormControl('', {
validators: [ Validators.required, Validators.pattern(regexPatterns.email) ],
asyncValidators: [ this.membershipsValidators.checkMembershipExists() ],
}),
});
这样,直到满足同步验证器的要求时,异步验证器才会触发。
答案 1 :(得分:2)
您可以在诺言中创建一个Observable来完成反跳操作。
这种逻辑可能不会被剪切和粘贴,但是应该使您接近。
import {distinctUntilChanged, debounceTime, switchMap} from 'rxjs/operators';
validate(c: FormControl) {
return new Promise(resolve => {
new Observable(observer => observer.next(c.value)).pipe(
debounceTime(600),
distinctUntilChanged(),
switchMap((value) => { return this.validateEmailService.validateEmail(value) })
).subscribe(
(res) => {
console.log(res);
if (res.valid) {
resolve(null);
} else {
resolve({
valid: {
valid: false
}
});
}
}
)
})
}