7

I'm trying to create a custom asynchronous validator, that goes to the server and checks if an email is already registered.

Unfortunately, it seems that the get request is never fired, because nothing happens. I've tried multiple console.logs inside subscribe, but they didn't run.

I've checked if that request works outside of the validator, and it does, so that's not the problem.

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { Response, Http } from '@angular/http';

 @Component({
     templateUrl: 'build/pages/welcome/signup/signup.html',
     providers: [AuthService, CustomValidators]
})
export class Signup {

     signupForm: FormGroup;

     constructor(private formBuilder: FormBuilder, private http: Http) {

         this.signupForm = formBuilder.group({
             'email': ['', Validators.required, this.checkEmail],
         }):
     }

     checkEmail(control: FormControl): Promise<any> {

          const promise = new Promise<any>(
             (resolve, reject) => {

                 this.http.get('/sharealead/main.php?action=checkEmail').subscribe(
                     (res: Response) => {
                         console.log('it never gets here');
                         console.log(res)
                         if (res.text() == 'already there') {
                             resolve({'emailTaken': true});
                         } else {
                             resolve(null);
                         }
                     },
                     (err) => {
                         console.log('it never gets here');
                         console.log(err);
                    }
                 )   
             }
         );
         return promise;
     }

}
KreepN
  • 8,528
  • 1
  • 40
  • 58
Alexandru Pufan
  • 1,842
  • 3
  • 26
  • 44

1 Answers1

9

It's because you reference the function and you lose the this context. You can use the bind method or a wrapping arrow function to fix that (link the function to the component instance):

this.signupForm = formBuilder.group({
         'email': ['', Validators.required, this.checkEmail.bind(this) ],
});

or

this.signupForm = formBuilder.group({
         'email': ['', Validators.required, (control:Control) => {
           return this.checkEmail(control);
         } ],
});

In your case, this doesn't contain an http property...

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Indeed, silly mistake, looks like I need one more lesson about this keyword in JavaScript (I'll mark your answer as accepted in about 8 minutes, when stackoverflow lets me) – Alexandru Pufan Aug 11 '16 at 15:44
  • You're welcome! Yes, the use of the `this` keyword in JavaScript is a bit specific... – Thierry Templier Aug 11 '16 at 15:46
  • Can you please also guide how to make such validator trigger on field blur only. In my case, its sending http requests even while I am typing email in the text box. So, before I finish typing my email address, it already has sent several request to server – Naveed Ahmed Sep 30 '16 at 23:03
  • For others with a similar symptom but different problem: I did not realize that async validators are only fired after *all* sync validators return valid (in angular 2.0.x at least). – msanford Oct 25 '16 at 15:57
  • for me it fires only once and doesn't care about model changes. Can you make a Plunker? – Toolkit Dec 25 '16 at 17:22