In my Angular app, I'm working on implementing async validation for a model-based form. I've simplified the form by removing other fields for clarity, but there are additional fields in the actual form. The goal is to check if a username is unique by calling a service asynchronously. The service is functioning correctly and the results are displayed in the console as expected.
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 check if a username already exists by making a remote call to a service and return true or false. The delay in validation should occur until the value is at least 4 characters long to allow the minLength(4)
validation message to show up as expected.
The validation messages are defined as follows:
formErrors = {
'username': ''
};
validationMessages = {
'username': {
'required': 'username is required',
'minlength': 'username must be at least 4 characters long',
'nameTaken': 'username already exists'
}
};
Although the minLength()
validation works as expected initially, once the input reaches 4 characters, an exception is thrown 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 occurs, no validation messages are displayed, and the minLength
validation does not work either.
The stack trace points to onValueChanged():111
, and the method is defined as follows:
onValueChanged(data?: any) {
if (!this.registerForm) {
return;
}
const form = this.registerForm;
for (const field of Object.keys(this.formErrors)) {
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 make synchronous and async validations work together seamlessly? I followed the approach of implementing an async validation method in the same component as the form, as suggested by Stack Overflow.
How can I display the
nameTaken
error message on the form? Isresolve({nameTaken: true});
the correct way to handle this in the validation Promise?
Any insights or suggestions on how to debug the current behavior would be greatly appreciated.