3
votes

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
2
for general anything you want to make aysnc await you have to use your function as async validationFunction() { await this.data = this.serviceCall() }GaurangDhorda
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(...)Andrei Gătej
Thanks @GaurangDhorda for reply. can you please provide some example.Code Explorer
Thanks @AndreiGătej for reply. I tried with only pipe but its not working.Code Explorer
stackblitz.com/edit/angular-5hwcff this stackblitz link may help youGaurangDhorda

2 Answers

2
votes

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 });
      }))
  }
}
0
votes

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.