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
Code Explorer
  • 65
  • 2
  • 7

2 Answers2

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 });
      }))
  }
}
AT82
  • 71,416
  • 24
  • 140
  • 167
  • Thanks @AJT82 but still every time it's returning false. – Code Explorer Nov 23 '19 at 13:32
  • 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"`. – AT82 Nov 23 '19 at 15:23
  • 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 – Code Explorer Nov 24 '19 at 09:35
  • `f.controls['Phone'].invalid` is then actually a formcontrol, right? Your form looks like: `this.f = this.fb.group({Phone: ''})`? Please provide a [mcve] it's really hard to help otherwise, but I suspect it should be `f.controls[Phone].invalid` – AT82 Nov 24 '19 at 09:38
  • Here's a working sample, which always returns error: https://stackblitz.com/edit/angular-h9k5qp-pd7ju3?file=app/input-overview-example.html Please fork the stackblitz and reproduce the issue there. – AT82 Nov 24 '19 at 09:45
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.
Akash
  • 4,412
  • 4
  • 30
  • 48