I am building a reactive form with a custom async validator. The validator uses angular's HTTP client to make a request to my server (which runs on node.js) and uses a callback function which receives the formcontrol's value. The idea is to check if the submitted ID which is input in the form already exists in the db or not. The server calls work correctly. The call is made, the return value (if exists) returns an object with a length of 1 and when it doesn't exist, it returns null.
Problem is, the state of the call remains as pending and prevents the form from turning into a valid state (I linked the submit button at the bottom of the form like so [disabled]="!newUser.valid" and since the status of the async validator remains pending, and the observable never completes, the button remains disabled).
I have tried subscribing to the observable but then I get the following error?: ((c: FormControl) => Subscription | Observable)[]' is not assignable to parameter of type 'AsyncValidatorFn | AsyncValidatorFn[]
Register.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { matchOtherValidator } from '../match-other-validator';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';
import { map} from 'rxjs/operators';
const tzAsyncValidator = (http: HttpClient) => (c: FormControl) => {
console.log(c.parent);
if (!c || String(c.value).length === 0) {
console.log("!c|| String (c.value).length ===0")
return of(null);
}
return http.get('http://localhost:4000/userIds/' + String(c.value))
.pipe(
map((ids: any[]) => {
console.log(ids);
if (ids.length === 1) {
console.log(c.parent.status);
console.log(c.status);
return { exists: true }
}
if (ids.length === 0) {
console.log(c.parent.status);
console.log(c.status);
return { exists: null};
}
}
)
)
.subscribe()
;
}
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
public newUser;
public verification;
constructor(private http: HttpClient) { }
ngOnInit() {
this.newUser = new FormGroup({
Tz: new FormControl('', [Validators.required, Validators.minLength(4), Validators.maxLength(9)], [tzAsyncValidator(this.http)]),
Email: new FormControl('', [Validators.required, Validators.email]),
PW: new FormControl('', [Validators.required, Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$')]),
PWVerification: new FormControl('', [Validators.required, Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'), matchOtherValidator('PW')])
})
}
}
Register.component.html
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
Sign up!
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Sign Up!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form [formGroup]="newUser" (ngSubmit)='onSubmit()' >
<label>ID</label>
<br>
<input type="text" placeholder="Please Enter Your ID" formControlName="Tz">
<br>
<label>Email</label>
<br>
<input type="email" placeholder="Please Enter Your Email" formControlName="Email">
<br>
<label>Password</label>
<br>
<input type="text" name="password" placeholder="Please Choose A Password" formControlName="PW" size="25">
<br>
<label>Resubmit Your Password</label>
<br>
<input type="text" name="confirmPassword" placeholder="Please Resubmit Your Password" formControlName="PWVerification" validateEqual="password" size="30" >
<br>
<input type="submit" class="btn btn-success" [disabled]="!newUser.valid" >
<br>
<span *ngIf="newUser.get('Email').invalid &&!newUser.get('Email').pristine">Your email does not look right</span>
<br>
<span *ngIf="newUser.get('Tz').errors?.minlength">Your ID must be at least 4 digits long</span>
<br>
<span *ngIf="newUser.get('Tz').errors?.maxlength">The maximum ID length is 9 digits</span>
<br>
<span *ngIf="newUser.get('PW').invalid&&!newUser.get('PW').pristine">Password must include at least one letter and one digit</span>
<br>
<span *ngIf="newUser.get('PWVerification').errors?.matchOther">Your submitted passwords don't match</span>
<br>
<span *ngIf="newUser.get('Tz').errors?.exists">This ID already exists</span>
</form>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>