I have a Custom Validator that validates if a user's email is unique or not.
I've searched for related topic on stackoverflow and internet, but no help
when I'm giving input in the form (sending the request), the request stays at pending state and doesnot resolves.
I've tested the backend in postman, its working as expected, the problem is at client or angular side.
The Validation function is as follows:
emailUniqueValidator (control: AbstractControl): Promise<{[key: string]: any}> | Observable<{[key: string]: any}> {
return new Promise((resolve, reject) => {
this.userService.checkEmailUnique(control.value).subscribe((response: Response) => {
const body = response.json();
if (body.found === false) {
resolve(null); // email is unique
} else {
reject({emailUniqueValidator: true}); // email is not unique
}
});
});
}
When i'm changing the form control's value, the pending class appears, but it sticks in forever instead of getting resolved.
I have the email form control as follows:
'email': new FormControl('', [
Validators.required,
Validators.email
], this.emailUniqueValidator.bind(this)
),
And my User service is as follows:
checkEmailUnique (email: string): Observable<Response> {
return this.http.post('http://localhost:3000/user/email', {email}, { withCredentials: true });
}
Why The validator is not resolving in time and staying pending forever?
EDIT:
The following code is getting value from the service just fine, i've checked it by logging the response into the console.
If the email is not present in the database, then it is getting resolved just fine, but if the email is already present, it is throwing an error and the state remains pending.
return new Promise((resolve, reject) => {
this.userService.checkEmailUnique(control.value).subscribe((response: Response) => {
console.log(response);
response.json().found ? reject({emailUniqueValidator: true}) : resolve(null);
}, (error: any) => reject({emailUniqueValidator: true}));
});
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.
Angular does not provide built-in type async Validation implmentation, it provides only for sync validation. The implementation of async validator is very similar to the sync validator. The only difference is that the async Validators must return the result of the validation as an observable or as Promise.
The async validator's validate method returns a Promise that resolves if validation passes and value is updated or rejects with an Error if validation does not pass and value is not updated. The async validator also has a hint field that returns a Promise that when resolved will return a hint.
Synchronous and asynchronous Validators are very similar - the main difference is that a sync Validator returns an error object instance directly, while the async version returns an Observable of the the same object. The most common use case for async Validators is doing a server validation via an HTTP Callback.
The observable never completes.
Try adding .first()
at the end.
emailUniqueValidator (control: AbstractControl): Observable<{[key: string]: any}> {
return this.userService.checkEmailUnique(control.value)
.map(r => r.json())
.map(r => (r.found) ? {emailUniqueValidator: true} : null)
.first();
}
Why are you going through the promise wrapping an observable head ache? try it like this:
emailUniqueValidator (control: AbstractControl): Observable<{[key: string]: any}> {
return this.userService.checkEmailUnique(control.value)
.map(r => r.json())
.map(r => (r.found) ? {emailUniqueValidator: true} : null);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With