简体   繁体   English

验证器返回 Promise 或 Observable:自定义异步验证器:Angular 8

[英]validator to return Promise or Observable : Custom async validator : Angular 8

I'm trying to create a custom async validator for my registration form where it checks if an email is a valid email or not using third party API.我正在尝试为我的注册表单创建一个自定义异步验证器,用于检查 email 是否是有效的 email 或不使用第三方 API。 this is ref link of the API website -这是 API 网站的参考链接 -

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

I am trying to implement it using RxJs debounceTime, distinctUntilChanged.我正在尝试使用 RxJs debounceTime, distinctUntilChanged 来实现它。 In the form control I have two more validations required and pattern.在表单控件中,我需要另外两个验证和模式。 But I am always getting this error - Error: Expected validator to return Promise or Observable.但我总是收到此错误 -错误:预期验证器返回 Promise 或 Observable。

I have searched several examples but nothing worked.我搜索了几个例子,但没有任何效果。 Thank you in advance.先感谢您。

Validator -验证器 -

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 }
                        }
                    })
                )
            }
        }
    }
}

Register Component -注册组件 -

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))
})

Why are you piping validators Observable from valueChanges Observable?为什么要从valueChanges Observable 管道验证器 Observable? That doesn't make much sense since the validator runs on valueChange and when it's dirty.这没有多大意义,因为验证器在 valueChange 上运行并且它是脏的。 And you are also returning the desired Observable only if the control is valid .只有当控件有效时,您才会返回所需的 Observable 。 So when sync validators mark the control as Invalid this one won't return the Observable.因此,当同步验证器将控件标记为无效时,此控件不会返回 Observable。 I guess that's what's causing the error.我想这就是导致错误的原因。

Try this approach:试试这个方法:

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 };
          }
        })
      );
    };
  }
}}

I'm using similar approach to this one in a project where I have to check export path on the filesystem.我在一个项目中使用与此类似的方法,我必须检查文件系统上的导出路径。 One thing I'm not so sure about is distinctUntilChanged.我不太确定的一件事是 distinctUntilChanged。 Isn't that filtered already不是已经过滤了吗

This what I have ended up with, which resolves my problem -这就是我最终得到的结果,它解决了我的问题 -

Validator -验证器 -

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;
        };
    }
}

Component TS -组件 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))
}) 

Component HTML -组件 HTML -

<div *ngIf="formcontrol.email.errors.isEmailInvalid">
   <p>Use a working E-mail address.</p>
</div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM