3

I am new to Angular 8 and trying to create custom async validator. Below is my code:

In my typescript file I am creating form field like below. I am using only async validator(no sync validator so passing 'null' as second parameter):

group.addControl(control.Name, this.fb.control('', null, this.phoneValidator));

Below is my async validator code:

phoneValidator(control: AbstractControl) {
    if(control.value == '' || control.value == undefined || control.value == null) {
      return null;
    }
    else {
      return this.phoneValidatorServiceCall(control.value)
        //.pipe(map((data: any) => {
        //  return (data.Response == "True" ? null : { phoneValidator: true });
        //}))
        .subscribe(data => {
            return (data.Response == "True" ? null : { phoneValidator: true });
        })
      }
   }

In above code I tried to use "Pipe" only it's not working so used "Subscribe" only but even this not working. Below is my service method:

phoneValidatorServiceCall(input): Observable<any> {
   return this.http.post<any>('http://xxxxxxxx:xxxx/validate/phone', { 'Text': input });
}

For showing error in html I am using below code:

<mat-form-field class="example-full-width">
<input #dyInput [formControlName]="Phone" matInput [placeholder]="Phone" [required]="IsRequiredField">

<!-- For showing validation message(s) (Start) -->
<mat-error *ngFor="let v of Config.Validators">
  {{ f.controls['Phone'].invalid }} // comes true only on error
  {{ f.controls['Phone'].hasError("phoneValidator") }} // always coming false even for wrong input
  <strong *ngIf="f.controls['Phone'].invalid && f.controls['Phone'].hasError('phoneValidator')">
    {{ My Message Here }}
  </strong>
</mat-error>
<!-- For showing validation message(s) (End) -->

I am facing two problems:

  1. It's not waiting for response from service. Somehow it's always return error from phoneValidator(control: AbstractControl) method
  2. Error message not showing on screen. f.controls['Phone'].hasError("phoneValidator") always coming false
5
  • for general anything you want to make aysnc await you have to use your function as async validationFunction() { await this.data = this.serviceCall() } Commented Nov 23, 2019 at 7:48
  • I don't think you are supposed to subscribe in your validator. You should only return the observable. Something like this: return this.phoneValidatorServiceCall(control.value).pipe(...) Commented Nov 23, 2019 at 8:51
  • Thanks @GaurangDhorda for reply. can you please provide some example. Commented Nov 23, 2019 at 10:24
  • Thanks @AndreiGătej for reply. I tried with only pipe but its not working. Commented Nov 23, 2019 at 10:24
  • stackblitz.com/edit/angular-5hwcff this stackblitz link may help you Commented Nov 23, 2019 at 10:47

2 Answers 2

4

You have been given good tips on how to solve your problem. Those gathered... So your current issues are:

Add return type of validator:

Observable<ValidationErrors | null>

Since that is what you are going to return.

So don't subscribe in the validator, instead return the observable. Also, you need to return of(null) when valid, since again... we need to return an observable. So modify your validator to:

import { of } from 'rxjs';

//....

phoneValidator(control: AbstractControl): Observable<ValidationErrors | null> {
  if (!control.value) {
    return of(null);
  } else {
    return this.phoneValidatorServiceCall(control.value)
      .pipe(map((data: any) => {
        return (data.Response == "True" ? null : { phoneValidator: true });
      }))
  }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @AJT82 but still every time it's returning false.
so is data.Response == "True" ever truthy? Have you checked that? What does console.log(data) produce? Also f.controls['Phone'].invalid might be wrong if you are doing [formControlName]="Phone".
data.Response comes "True" when phone number is validate else it returns "False". Response is correct but f.controls['Phone'].invalid is always true. That is problem
f.controls['Phone'].invalid is then actually a formcontrol, right? Your form looks like: this.f = this.fb.group({Phone: ''})? Please provide a minimal reproducible example it's really hard to help otherwise, but I suspect it should be f.controls[Phone].invalid
Here's a working sample, which always returns error: stackblitz.com/edit/angular-h9k5qp-pd7ju3?file=app/… Please fork the stackblitz and reproduce the issue there.
0

There are couple of problems -

  1. The return type of phoneValidator should be Promise<ValidationErrors | null> | Observable<ValidationErrors | null>.
  2. Do something like below so that you return an observable and check if your second problem gets solved -

return observableOf({ phoneValidator: true });

  1. Use pipe and map your response.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.