I'm trying to do an async validation on a model based form in angular. For simplicity I have removed all other fields of the form. In the actual example there are more fields.
buildForm(): void {
this.registerForm = this.fb.group({
'username':
[this.user.username, [Validators.required, Validators.minLength(4)],
[this.validateUsernameUnique.bind(this)]]
});
this.registerForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); // set validation messages now
}
the validateUsernameUnique() method should call a service and remotely check if a username already exists and return true or false. The service is working properly, its result appear on the console as expected.
validateUsernameUnique(control: AbstractControl) {
clearTimeout(this.usernameCheckTimeout);
return new Promise((resolve) => {
this.usernameCheckTimeout = setTimeout(() => {
if (control.value.length >= 4) {
this.userService.doesUsernameExist(control.value)
.then(res => {
if (!res) {
resolve(null);
} else {
resolve({nameTaken: true});
}
});
} else {
resolve(null);
}
}, 1000);
});
}
I'm trying to skip this validation until the value is >= 4, because I want the minLength(4)-Validation to show up until then.
The validation messages are defined like this:
formErrors = {
'username': ''
};
validationMessages = {
'username': {
'required': 'username is required',
'minlength': 'username must be at least 4 characters long',
'nameTaken': 'username does already exist'
}
};
The minLength()-Checks works at the beginning as expected and username must be at least 4 characters long shows up on the form too. But when I reach 4 characters, I get an exception in the console:
TypeError: can't convert null to object
Stack trace:
UserRegisterComponent.prototype.onValueChanged@webpack-internal:///./src/app/user/user-register/user-register.component.ts:111:39
UserRegisterComponent.prototype.buildForm/<@webpack-internal:///./src/app/user/user-register/user-register.component.ts:63:49
After the error occured, no validation message is displayed anymore, the minLength-Validation doesn't also work anymore.
The stackTrack reported the problem in onValueChanged():111, this method looks like this:
onValueChanged(data?: any) {
if (!this.registerForm) {
return;
}
const form = this.registerForm;
for (const field of Object.keys(this.formErrors)) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key of Object.keys(control.errors)) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
How can I get synchronous and async validations get to work side by side? I got the approach with a async-Validation-Method in the same component as the form also from SO.
How can I get the
nameTaken-errorMessage to appear on the form? Isresolve({nameTaken: true});in the validation Promise the wrong approach?
Any input appreciated. Don't know exactly how I can possibly debug the currenct behaviour to get a idea what the problem is.