Reputation: 11851
I am trying to create a custom form validator, but I keep getting this error Cannot read property 'value' of null. I have been really struggling with is issue for days now and here is my FormGroup:
this.step1Form = this.fb.group({
username: new FormControl('', {
validators: [Validators.required,
Validators.minLength(4),
this.checkUsername.bind(this)],
}),
email: new FormControl('', {
validators: [Validators.required,
Validators.pattern("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")],
}),
password: new FormControl('', {
validators: [Validators.required,
Validators.minLength(8)],
}),
repeat: new FormControl('', {
validators: [Validators.required,
Validators.minLength(8)],
}),
});
Here is my checkUsername method
checkUsername(g: FormGroup) {
return this.dataService.checkUsername(g.get('username').value).pipe(map(data => {
return typeof data["error"] != 'undefined' ? null : {'taken': true};
}));
}
and here is the checkUsername method in this.dataService
checkUsername(username):Observable<any> {
return this.http.get(globals.baseUrl+'/user/' + username, {headers:this.utilService.getHeadersJson()}).map(this.utilService.map);
}
And I get the error:
Cannot read property 'value' of null
on this line
return this.dataService.checkUsername(g.get('username').value).pipe(map(data => {
What am I doing wrong? I have tried without the pipe like so
checkUsername(g: FormGroup) {
return this.dataService.checkUsername(g.get('username').value).subscribe(data => {
return typeof data["error"] != 'undefined' ? null : {'taken': true};
});
}
but that didnt work, I have also tried my validator in different positions like so:
this.step1Form = this.fb.group({
username: new FormControl('', {
validators: [Validators.required,
Validators.minLength(4)],
}),
email: new FormControl('', {
validators: [Validators.required,
Validators.pattern("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")],
}),
password: new FormControl('', {
validators: [Validators.required,
Validators.minLength(8)],
}),
repeat: new FormControl('', {
validators: [Validators.required,
Validators.minLength(8)],
}),
}, { validator: this.checkUsername.bind(this)});
Also didnt work.
PLEASE HELP!
I have also tried this:
username: new FormControl('', {
validators: [Validators.required,
Validators.minLength(4)],
asyncValidator: [this.checkUsername.bind(this)],
}),
got this error:
Argument of type '{ validators: ValidatorFn[]; asyncValidator: any[]; }' is not assignable to parameter of type 'ValidatorFn | AbstractControlOptions | ValidatorFn[]'. Object literal may only specify known properties, and 'asyncValidator' does not exist in type 'ValidatorFn | AbstractControlOptions | ValidatorFn[]'.
Upvotes: 1
Views: 4174
Reputation: 597
Angular reactive forms call the validators immediately and often. The cross-field validator on your form group will begin to validate as each child control is instantiated by the framework.
To prevent it from throwing premature validation errors, you'll probably want to ensure that the control in question has been instantiated, like so:
checkUsername(g: FormGroup) {
if (!g || !g.get('username')) {
return null;
}
return this.dataService.checkUsername(g.get('username').value).subscribe(data => {
return typeof data["error"] != 'undefined' ? null : {'taken': true};
});
}
Your 2nd attempt seems like a better direction to go, however, because it's an asynchronous validator for the 'username' control, but you have a typo in the asyncValidators property (missing the 's'). You also likely don't need to .bind(this) if you're not referencing "this" in the function.
username: new FormControl('', {
validators: [Validators.required, Validators.minLength(4)],
asyncValidators: [this.checkUsername]
})
Then your validator is just handling a single form control instead of the whole group, something like this:
checkUsername(c: FormControl) {
if (!c) { return null; }
return this.dataService.checkUsername(c.value).subscribe(data => {
return typeof data["error"] != 'undefined' ? null : {'taken': true};
});
}
Upvotes: 1