Angular 4: reactive form control is stuck in pending state with a custom async validator

后端 未结 3 1630
无人及你
无人及你 2020-12-31 00:02

I am building an Angular 4 app that requires the BriteVerify email validation on form fields in several components. I am trying to implement this validation as a custom asyn

相关标签:
3条回答
  • 2020-12-31 00:26

    I've been doing it slightly differently and faced the same issue.

    Here is my code and the fix in case if someone would need it:

      forbiddenNames(control: FormControl): Promise<any> | Observable<any> {
        const promise = new Promise<any>((resolve, reject) => {
          setTimeout(() => {
            if (control.value.toUpperCase() === 'TEST') {
              resolve({'nameIsForbidden': true});
            } else {
    
              return null;//HERE YOU SHOULD RETURN resolve(null) instead of just null
            }
          }, 1);
        });
        return promise;
      }
    
    0 讨论(0)
  • 2020-12-31 00:26

    So what I did was to throw a 404 when the username was not taken and use the subscribe error path to resolve for null, and when I did get a response I resolved with an error. Another way would be to return a data property either filled width the username or empty through the response object and use that insead of the 404

    Ex.

    In this example I bind (this) to be able to use my service inside the validator function

    An extract of my component class ngOnInit()

    //signup.component.ts
    
    constructor(
     private authService: AuthServic //this will be included with bind(this)
    ) {
    
    ngOnInit() {
    
     this.user = new FormGroup(
       {
        email: new FormControl("", Validators.required),
        username: new FormControl(
          "",
          Validators.required,
          CustomUserValidators.usernameUniqueValidator.bind(this) //the whole class
        ),
        password: new FormControl("", Validators.required),
       },
       { updateOn: "blur" });
    }
    

    An extract from my validator class

    //user.validator.ts
    ...
    
    static async usernameUniqueValidator(
       control: FormControl
    ): Promise<ValidationErrors | null> {
    
     let controlBind = this as any;
     let authService = controlBind.authService as AuthService;  
     //I just added types to be able to get my functions as I type 
    
     return new Promise(resolve => {
      if (control.value == "") {
        resolve(null);
      } else {
        authService.checkUsername(control.value).subscribe(
          () => {
            resolve({
              usernameExists: {
                valid: false
              }
            });
          },
          () => {
            resolve(null);
          }
        );
      }
    });
    
    ...
    
    0 讨论(0)
  • 2020-12-31 00:29

    There's a gotcha!

    That is, your observable never completes...

    This is happening because the observable never completes, so Angular does not know when to change the form status. So remember your observable must to complete.

    You can accomplish this in many ways, for example, you can call the first() method, or if you are creating your own observable, you can call the complete method on the observer.

    So you can use first()

    UPDATE TO RXJS 6:

    briteVerifyValidator(service: Service) {
      return (control: AbstractControl) => {
        if (!control.valueChanges) {
          return of(null);
        } else {
          return control.valueChanges.pipe(
            debounceTime(1000),
            distinctUntilChanged(),
            switchMap(value => service.getData(value)),
            map(data => {
              return data.status === 'invalid' ? { invalid: true } : null;
            })
          ).pipe(first())
        }
      }
    }
    

    A slightly modified validator, i.e always returns error: STACKBLITZ


    OLD:

    .map(data => {
       return data.status === 'invalid' ? { invalid: true } : null;
    })
    .first();
    

    A slightly modified validator, i.e always returns error: STACKBLITZ

    0 讨论(0)
提交回复
热议问题