Reputation: 18749
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.
Upvotes: 1
Views: 871
Reputation: 18749
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;
}));
};
}
Upvotes: 2