title: Angular 2 Async Custom Validation with Web API call
body: <p>I am trying to create a async custom validator to check if a username already exist in a signup form. I have created a service class which calls the <strong>Web API</strong> (as below) to check the unique user name. </p>
  
  <p>I also created a <strong>async custom validator</strong> which suppose to call the service and perform the validation. However I am stuck trying to understand how to inject the service into the validator. The service also get injected with <strong>Http</strong>. </p>
  
  <p>Anyone has any idea how this validation can be done properly?</p>
  
  <p>-Alan-</p>
  
  <h2>Custom Validator</h2>
  
  <pre><code>export class UserNameValidators {
      static shouldBeUnique(control: FormControl) {
             ....
             //Need to call the Signup service here
          }
      }
  </code></pre>
  
  <h2>Service</h2>
  
  <pre><code>@Injectable()
  export class SignUpService
  {
          constructor(private http: Http) {
  
            }
  shouldBeUnique(username: string): Observable&lt;boolean&gt; {
          let headers = new Headers();
          headers.append('Content-Type', 'application/x-www-form-urlencoded');
          let options = new RequestOptions({ headers: headers });
  
                 return this.http.post('localhost/authentication/api/accounts/user/' + username, '', options)
              .map((response: Response) =&gt; {
                  let result = response.toString();
                  if (result === 'true')
                      return true
  
                  return false;
              })
              .catch((error: any) =&gt; {
                  if (error.status === 400) {
                      var cleandata = error._body
                          .replace(/\\n/g, "\\n")
                          .replace(/\\'/g, "\\'")
                          .replace(/\\"/g, '\\"')
                          .replace(/\\&amp;/g, "\\&amp;")
                          .replace(/\\r/g, "\\r")
                          .replace(/\\t/g, "\\t")
                          .replace(/\\b/g, "\\b")
                          .replace(/\\f/g, "\\f");
  
                      cleandata = cleandata.replace(/[\u0000-\u001F]+/g, "");
  
                      return Observable.throw(new Error("Unknown Error"));
                  }
  
              });
      }
  }
  </code></pre>
  
  <h2>Update</h2>
  
  <h2>App.Module</h2>
  
  <pre><code>@NgModule({
      imports     : [BrowserModule, HomeModule, SignupModule,signupRouting, routing],
      declarations: [AppComponent],
      providers   : [AuthService, AuthGuard, SignupService],
      bootstrap   : [AppComponent]
  })
  </code></pre>
  
  <h2>Custom Validator</h2>
  
  <pre><code>export class UserNameValidators {
  
      constructor(private service: SignupService) { }
  
      shouldBeUnique(control: FormControl) {
          return new Promise((resolve, reject) =&gt; {
  
              this.service.shouldBeUnique(control.value).subscribe(
                  data =&gt; {
                      if (data.length == 0 || data.length == 1) {
                          resolve(null);
                      } else {
                          resolve({ shouldBeUnique: true });
                      }
                  },
                  err =&gt; {
                      resolve({ shouldBeUnique: true });
                  }
              )
          });
  
      }
  }
  </code></pre>
  
  <h2>Signup.component</h2>
  
  <pre><code>export class SignupComponent implements OnInit {
      form: FormGroup;
      signedUp: boolean = false;
      error = '';
  
      constructor(private fb: FormBuilder, private router: Router, private signupService: SignupService) { }
  
      ngOnInit() {
          this.form = this.fb.group({
              firstname: ['', Validators.required],
              lastname: ['', Validators.required],
              username: ['', Validators.compose([Validators.required, UserNameValidators.notValidEmail]), new UserNameValidators(this.signupService).shouldBeUnique],
  
              password: ['', Validators.compose([Validators.required, UserNameValidators.cannotContainSpace])],
              confirmpassword: ['', Validators.compose([Validators.required, UserNameValidators.cannotContainSpace])]
          }, { validator: this.matchingPasswords('password', 'confirmpassword') });
      }
  }
  </code></pre>