Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Custom Async Validator stays in pending state

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}));
});
like image 780
Himanshu Mittal Avatar asked Oct 17 '17 18:10

Himanshu Mittal


People also ask

Why form status is pending in Angular?

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.

What is asynchronous validation in angular?

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.

What is asynchronous validator?

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.

What is the difference between synchronous and asynchronous Validators in angular?

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.


2 Answers

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();
 }
like image 142
Joey V. Avatar answered Nov 15 '22 21:11

Joey V.


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);
 }
like image 39
bryan60 Avatar answered Nov 15 '22 19:11

bryan60