Custom Validator Not Working in Angular Reactive Form
I am trying to create a custom validator that checks if a phone number already exists. My code is as follows:
Validation Function
phoneValidator() {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
if (!control.valueChanges || control.pristine) {
return of(null);
} else {
this.userMgt.phoneExists(control.value).pipe(
distinctUntilChanged(),
debounceTime(600))
.subscribe((res: ApiResponse<any>) => {
debugger
if(!res.hasErrors()) {
if(res.data == true) {
return { phoneExists: true };
}
else {
return null
}
}
})
}
};
}
The API from the backend that verifies the phone number:
phoneExists(phoneNo: string): Observable<ApiResponse<user>> {
return this.clubApiGet(`/profile/isPhoneNumberExists?phoneNo=${phoneNo}`)
}
My Form Group
private fb: FormBuilder,
defaultUser: User = {
phoneNo: ""
};
ngOnInit(): void {
this.initUserForm();
}
initUserForm() {
this.userForm = this.fb.group({
phone: [
this.defaultUser.phoneNo,
Validators.compose([
Validators.required,
Validators.minLength(11),
Validators.maxLength(14),
this.phoneValidator()
]),
]
});
}
My HTML
<div class="form-group row">
<label class="col-xl-3 col-lg-3 col-form-label">Contact Phone
<span class="text-danger">*</span>
</label>
<div class="col-lg-9 col-xl-6">
<div class="input-group input-group-lg input-group-solid">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="fas fa-phone-alt text-primary"></i>
</span>
</div>
<input
type="text"
class="form-control form-control-lg form-control-solid"
value="+35278953712"
placeholder="Phone"
formControlName="phone"
[ngClass]="{ 'is-in valid': userForm.controls['phone'].invalid&&
userForm.controls['phone'].errors}"
>
</div>
<ng-container [ngTemplateOutlet]="formError" [ngTemplateOutletContext]="{
validation: 'required',
message: 'Phone Number is required',
control: userForm.controls['phone']
}"></ng-container>
<ng-container [ngTemplateOutlet]="formError" [ngTemplateOutletContext]="{
validation: 'minlength',
message: 'Phone Number should at least be 11 characters',
control: userForm.controls['phone']
}"</ng-container>
<ng-container [ngTemplateOutlet]="formError" [ngTemplateOutletContext]="{
validation: 'maxlength',
message: 'Phone Number cannot exceed 14 characters',
control: userForm.controls['phone']
}"</ng-container>
// THIS VALIDATION CHECK DOES NOT WORK
<div class="text-danger" *ngIf="userForm.controls['phone']?.errors?.phoneExists">
This Phone Number is already registered to a user
</div>
</div>
</div>
I cannot figure out where the problem occurs. The API is working fine but the error message doesn't show. I would really appreciate any help. Thank You!
- You have added
this.phoneValidator()
as part of synchronous validators. It should be part of Async validators:
phone: [
this.defaultUser.phoneNo,
Validators.compose([
Validators.required,
Validators.minLength(11),
Validators.maxLength(14)
]),
[this.phoneValidator()]
]
- You don't need to subscribe, but rather return an Observable from the async validator function:
// else block
return this.userMgt.phoneExists(control.value).pipe( // added 'return'
distinctUntilChanged(),
debounceTime(600),
map((res: ApiResponse<any>) => { // using map operator
debugger
if (!res.hasErrors()) {
if (res.data == true) {
return { phoneExists: true };
}
else {
return null
}
}
return null; // added return statement
})
);