1

I have a basic form that checks if an email address exists as an Async Validator.

ngOnInit(): void {
      this.form = new FormGroup({
        email: new FormControl('',
        [
          Validators.required,
          Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$')
         ],
         [
           pendingPortfolioUserRequestValidator(this.portfolioInviteService, this.data.portfolioId)
          ])
      });
  }

The Async Validator pendingPortfolioUserRequestValidator looks like this

export function pendingPortfolioUserRequestValidator(portfolioInviteService: PortfolioInviteService,
  portfolioId: number): AsyncValidatorFn {
  return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    return portfolioInviteService.checkUserIsPending(portfolioId, control.value).pipe(map((email) => {
      return (email) ? {'pendingUserExists': true} : null;
    }));
  };
}

The line of code that determines whether the email exists or not (return (email) ? {'pendingUserExists': true} : null;) is getting hit, but when I check the errors collection, it's giving null as the value.

I have also tried to use a promise, but nothing seems to work.

2
  • Check what value email actually gives in the response? Commented Sep 5, 2021 at 11:14
  • The response is returning ‘true’ from the api when the email exists, otherwise false. The problem is that the errors collection on the form control is empty, thus the validation passes. Commented Sep 5, 2021 at 13:13

1 Answer 1

3

On further reading, and trying to get to the bottom of this, I found a pending property. When I checked the state of this, the property was still pending even though it looked like the validation was complete. This part of the article helped with the understanding:

Asynchronous validators implement the AsyncValidatorFn and AsyncValidator interfaces. These are very similar to their synchronous counterparts, with the following differences.

  • The validate() functions must return a Promise or an observable,
  • The observable returned must be finite, meaning it must complete at some point. To convert an infinite observable into a finite one, pipe the observable through a filtering operator such as first, last, take, or takeUntil.

I needed to add a call to take(1), and this has solved the issue.

Updated Code:

export function pendingPortfolioUserRequestValidator(portfolioInviteService: PortfolioInviteService,
  portfolioId: number): AsyncValidatorFn {
  return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    return portfolioInviteService.checkUserIsPending(portfolioId, control.value).pipe(
      take(1),
      map(
      (email: boolean) => {
      return (email) ? {'pendingUserExists': true} : null;
    }));
  };
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.