-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(input): improve html5 validation support #7937
Conversation
var viewValue = ctrl.$viewValue; | ||
|
||
$timeout.cancel(pendingDebounce); | ||
if (ctrl.$$lastCommittedViewValue === viewValue) { | ||
if (!revalidate && ctrl.$$lastCommittedViewValue === viewValue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC @petebacondarwin / @shahata --- It's possible for the old value and new value to be the same here, because HTML5 will report controlls suffering from bad input's value as the empty string --- but we should revalidate anyways just so the native HTML validators do their business.
However, it may not be desirable to update the "last committed value" in that case, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it mean for the native validators to do their business?
Is the question, should we set the last committed value to the empty string if the HTML5 validation fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We occasionally need to revalidate, even if the actual value hasn't changed. But I guess by that point, the last committed value is probably the empty string anyways. So maybe it's not worth worrying about
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably have some unit tests that demonstrate the various scenarios - at least for posterity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- If I understand correctly, this is important only in case the html5 validators report a different validity error the second time this is invoked and we want to update
ctrl.$error
with the latest validation problem. If this is the case, maybe we should consider removing therevalidate
parameter and compare the validity state here with the previous committed one. I don't like it very much, but I think it is a bit better then passingrevalidate
all this way. Another option is to run the validators no matter what in case the string is empty. - Actually, passing the
revalidate
is a problem any way, since it will not work in caseng-model-options="{updateOn: 'blur'}"
. In this case, this function will be invoked by the blur trigger handler, which will not pass therevalidate
argument...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not every time, only when prevValue==newValue && prevValue=='' && (prevValidity.badInput || newValidity.badInput)
or something like this. This made me realize that there is also the case where a value was invalid and now it is just empty - this case should also be revalidated and currently it is not covered imo. Anyway, even if you don't diff ValidityState, what do you think about the second point I mentioned? The revalidate thing will not work correctly in case of updateOn: 'blur'
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, the ngModelOptions stuff added a ton of complexity to this machinery that didn't exist previously, and there were no tests against it breaking the html5 validation stuff because it's not really possible to test without without the hacks here (those hacks probably should have existed initially, but hey).
So what we need to do is figure out a way for them to work well together in tandum.
Computing a diff between ValidityState objects is problematic, because A) ValidityState keys are not always enumerable (Firefox) which makes a diffing algorithm difficult and makes us have to keep track of possible ValidityState flags which are not necessarily never changing, maintenance hell, and B) it's just a stupid amount of work that isn't really needed anywhere.
You're right that this is broken in the case of invalid -> empty, so that's fixable, but the gunk with ngModelOptions is a lot harder because that piece of machinery is overly complex and not built with constraint validation in mind, which is why you guys are CC'd here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree diffing the ValidityState is not pretty/cheap and I really don't like it too, I'm just trying to think of a way to do this that will work in all cases. What about the option to run all validators anyway in case the string is empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with that, at least in the case where we're using html5 validators
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
@@ -1093,7 +1107,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { | |||
} | |||
}); | |||
|
|||
addNativeHtml5Validators(ctrl, 'number', element); | |||
addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ignoreFlags
parameter doesn't seem to be used at all. If we set it to []
here rather than null
then we could remove the if(flags)
line in the testFlags()
function above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's needed for other types, eventually we will want to do this for required
validation too (at the bare minimum), and we don't want to invalidate required
if we have badInput
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This is because of the really, really stupid constraint validation API, it makes zero sense, but it's what we've got =()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if we insist that these parameters are always arrays then we don't need the check right? Is there anywhere that a null is going to be passed where we can't insist that it is an empty array instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question is whether you prefer testing if flags is null, or if you prefer creating an extra global object --- my preference is on the former here
This CL improves mocking support for HTML5 validation, and ensures that it works correctly along with debounced commission of view values.
LGTM |
alright, checking this in today, since it's pretty broken in 1.2.x too --- if it needs to be cleaned up I think that can be done before the release, but this should be ok |
This CL improves mocking support for HTML5 validation, fixes the behaviour which invokes validators. Previously, an input would only be revalidated if either its value changed, or if it was the empty string but did not suffer from bad input --- now, it will be revalidated if either the value has changed, or the value is the empty string, there is a ValidityState for the element, and that ValidityState is being tested by one of the validators in the pipeline. Closes #7937 Closes #7957
@caitp I thought we agreed on changing the |
nobody understands how updateOn works other than the two of you, so figure something out to make that work. ngModelOptions should have never shipped without working with this if there had been tests in place before --- now there are tests, now we know we can make it work. |
okay, so would you like me to send a PR that fixes this? |
yes, along with the e2e tests you wrote already =) |
np |
This CL improves mocking support for HTML5 validation, and ensures that it works correctly along with debounced commission of view values. Closes angular#7936 Closes angular#7937
This CL improves mocking support for HTML5 validation, and ensures that it
works correctly along with debounced commission of view values.
Closes #7936