0

我正在尝试为我的注册表单创建一个自定义异步验证器,用于检查电子邮件是否为有效电子邮件或不使用第三方 API。这是 API 网站的参考链接 -

https://www.zerobounce.net/email-validation-api.html

我正在尝试使用 RxJs debounceTime, distinctUntilChanged 来实现它。在表单控件中,我需要另外两个验证和模式。但我总是收到此错误 -错误:预期验证器返回 Promise 或 Observable。

我搜索了几个例子,但没有任何效果。先感谢您。

验证器 -

export class UniqueEmailValidator{
   static createValidator(_ajaxService : AjaxService){
        return (control : AbstractControl) =>{
            const apiKey = environment.emailValidatationKey;
            const baseUrl = 'https://api.zerobounce.net/v2/validate?';
            if(control.valid){
                return control
                .valueChanges
                .pipe(
                    debounceTime(800),
                    distinctUntilChanged(),
                    switchMap((email : string) => _ajaxService.apiCall('', `${baseUrl}api_key=${apiKey}&email=${email}&ip_address=''`, 'GET', true)),
                    map(res => res.json()),
                    map((validationStatus : any) => {
                        if (
                            validationStatus.status == "valid" &&
                            validationStatus.mx_found == "true"
                        ) {
                            return null
                        } else {
                            return { isEmailInvalid : true }
                        }
                    })
                )
            }
        }
    }
}

注册组件 -

this.registration = this._formBuilder.group({
  firstName: new FormControl('', [
    Validators.required,
    Validators.pattern('^[a-z A-Z]+$')
  ]),
  lastName: new FormControl('', [
    Validators.required,
    Validators.pattern('^[a-z A-Z]+$')
  ]),
  email: new FormControl('', [
    Validators.required,
    Validators.pattern('[A-Za-z0-9._%-]+@[A-Za-z0-9._%-]+\\.[a-z]{2,3}')
  ],UniqueEmailValidator.createValidator(this._ajaxService))
})
4

2 回答 2

0

为什么要从 Observable 管道验证器valueChangesObservable?这没有多大意义,因为验证器在 valueChange 上运行并且它是脏的。只有当控件有效时,您才会返回所需的 Observable 。因此,当同步验证器将控件标记为无效时,此控件不会返回 Observable。我想这就是导致错误的原因。

试试这个方法:

export class UniqueEmailValidator {
  static createValidator(_ajaxService: AjaxService) {
    return (control: AbstractControl) => {
      const apiKey = environment.emailValidatationKey;
      const baseUrl = 'https://api.zerobounce.net/v2/validate?';

      return timer(800).pipe(
        concatMap((email: string) =>
          _ajaxService.apiCall('', `${baseUrl}api_key=${apiKey}&email=${email}&ip_address=''`, 'GET', true)
        ),
        map(res => res.json()),
        map((validationStatus: any) => {
          if (validationStatus.status == 'valid' && validationStatus.mx_found == 'true') {
            return null;
          } else {
            return { isEmailInvalid: true };
          }
        })
      );
    };
  }
}}

我在一个项目中使用与此类似的方法,我必须检查文件系统上的导出路径。我不太确定的一件事是 distinctUntilChanged。不是已经过滤了吗

于 2021-01-21T06:03:48.450 回答
0

这就是我最终得到的结果,它解决了我的问题 -

验证器 -

export class UniqueEmailValidator {
    static createValidator(_ajaxService: AjaxService) {
        let validatorSubject$ = new Subject();
        let debouncedSubject$ = new Subject<string>();

        debouncedSubject$
        .pipe(debounceTime(500), distinctUntilChanged())
        .subscribe((email: string) => {
            const apiKey = environment.emailValidatationKey;
            const baseUrl = 'https://api.zerobounce.net/v2/validate?';
            _ajaxService.apiCall('', `${baseUrl}api_key=${apiKey}&email=${email}&ip_address=''`, 'GET', true).subscribe({
                next: (validationData : IEmailValidation) => {
                    if (
                        validationData.status == "valid" &&
                        validationData.mx_found == "true" &&
                        (
                          validationData.sub_status == "alias_address" ||
                          validationData.sub_status == ""
                        )
                    ) {
                        return null
                    } else {
                        return { isEmailInvalid : true }
                    }
                },
                error: (validationFailed) => {
                    console.log(
                        "Failed to validate the Email Address",
                        validationFailed
                    );
                },
            });
        });

        return (
            control: AbstractControl
        ):
        | Promise<ValidationErrors | null>
        | Observable<ValidationErrors | null> => {
            debouncedSubject$.next(control.value);
            let promise = new Promise<any>((resolve, reject) => {
              validatorSubject$.subscribe((result) => resolve(result));
            });
            return promise;
        };
    }
}

组件 TS -

this.registration = this._formBuilder.group({
  firstName: new FormControl('', [
    Validators.required,
    Validators.pattern('^[a-z A-Z]+$')
  ]),
  lastName: new FormControl('', [
    Validators.required,
    Validators.pattern('^[a-z A-Z]+$')
  ]),
  email: new FormControl('', [
    Validators.required,
    Validators.pattern('[A-Za-z0-9._%-]+@[A-Za-z0-9._%-]+\\.[a-z]{2,3}')
  ],UniqueEmailValidator.createValidator(this._ajaxService))
}) 

组件 HTML -

<div *ngIf="formcontrol.email.errors.isEmailInvalid">
   <p>Use a working E-mail address.</p>
</div>
于 2021-01-30T09:10:52.557 回答