I am trying to validate a field with synchronous and async validation. There is a problem occuring when the field changes before the async validation ends. If after changing the validation returns an error (the field is invalid), but there is still an async validation running (from a previous value), and the async validation return after that, the field becomes valid again, but should stay invalid.
Plunker
I created a plunker to show this occurrence: http://plnkr.co/edit/q0jttO
The plunker code that create the FormGroup (using the new forms) with the validators is:
this.formGroup = formBuilder.group({
id: [''],
name: [
'',
(c: AbstractControl) => (c.value != null && c.value.length >= 3) ? null : {
key: 'name_minlength',
msg: 'The name must have at least 3 characters'
}
],
email: [
'',
(c: AbstractControl) => {
if (c.value != null && c.value.length !== 4) {
console.log('sync - success -> ' + c.value);
return null; // OK
} else {
console.log('sync - error -> ' + c.value);
return {
key: 'email_4char',
msg: 'The email must not have 4 characters'
};
}
},
(c: AbstractControl) => new Promise(
resolve => {
console.log('async started -> ' + c.value);
setTimeout(() => {
if (c.value !== 'aaa') {
console.log('async ended - success -> ' + c.value);
resolve(null); //OK
} else {
console.log('async ended - error -> ' + c.value);
resolve({
key: 'email_aaa',
msg: 'The email must be different than "aaa"'
});
}
}, 2000)
}
)
]
});
I don't know if this something that I forgot to do or that I did wrong, or if it's a problem of angular 2 (after all, it's still in beta).
Steps to Simulate
I made the steps to simulate this problem simple making the validation give an async error if aaa
is typed and a sync error if aaaa
is typed.
You can reproduce these steps in the plunker (you can see the logs of the validations in the browser console):
- Typing
aa
in the email field (the field is valid). - Then you type another
a
and wait for the validation (the async validation will show an error). - Then type another
a
(becomingaaaa
), and the sync validation will show an error (until now it's alright, but wait). - Delete the last 2
a
s to becomeaa
again. - Type 1
a
and then anothera
before the validation end.
The error message from the validation with aaaa
will show, but then the async validation will end and the message will disappear.
Logs
Sync Validation where email must not have 4 characters (just for example purposes) and an error message must be shown:
1) Shows the error (console logs when typing slowly):
sync - success -> aaa
async started -> aaa
async ended - error -> aaa
sync - error -> aaaa
2) Shows the error, but then hide it after the previous async call return with success (console logs when typing faster):
sync - success -> aaa
async started -> aaa
sync - error -> aaaa
async ended - success -> aaaa
It's not only the error not showing, but the class also stays as ng-valid (should be invalid, the error is not shown because of it).
This also occurs if I change the async validator to only return valid (resolve with null
), because what happens is that the async return from the previous value changes the validation result of the last value typed (this shouldn't happen; only the validations related to the last value should define its validity):
resolve => {
console.log('async started -> ' + c.value);
setTimeout(() => {
console.log('async ended -> ' + c.value);
resolve(null); //OK
}, 2000)
}
Is there a way to make the field stay invalid even if the async validation from a previous value ends after a validation error from the last value typed?