This repository has been archived by the owner on Apr 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(input): improve html5 validation for ngModelOptions #7976
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2228,6 +2228,18 @@ describe('input', function() { | |
expect(inputElm).toBeInvalid(); | ||
}); | ||
|
||
it('should invalidate number with ngModelOptions if suffering from bad input', function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another test case similar to the one from line 2274, but with ngModelOptions, would be useful There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
compileInput('<input type="number" ng-model="age" ' + | ||
'ng-model-options="{updateOn: \'blur\'}"/>', { | ||
valid: false, | ||
badInput: true | ||
}); | ||
|
||
changeInputValueTo('10a'); | ||
browserTrigger(inputElm, 'blur'); | ||
expect(scope.age).toBeUndefined(); | ||
expect(inputElm).toBeInvalid(); | ||
}); | ||
|
||
it('should validate number if transition from bad input to empty string', function() { | ||
var validity = { | ||
|
@@ -2243,6 +2255,22 @@ describe('input', function() { | |
expect(inputElm).toBeValid(); | ||
}); | ||
|
||
it('should validate when bad input number with ngModelOptions changes to empty', function() { | ||
var validity = { | ||
valid: false, | ||
badInput: true | ||
}; | ||
compileInput('<input type="number" ng-model="age" ' + | ||
'ng-model-options="{updateOn: \'blur\'}"/>', validity); | ||
changeInputValueTo('10a'); | ||
browserTrigger(inputElm, 'blur'); | ||
validity.badInput = false; | ||
validity.valid = true; | ||
changeInputValueTo(''); | ||
browserTrigger(inputElm, 'blur'); | ||
expect(scope.age).toBeNull(); | ||
expect(inputElm).toBeValid(); | ||
}); | ||
|
||
describe('min', function() { | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@shahata thinking about this more, I don't think this is right.
We have a number of different scenarios where we need to revalidate: when an interpolated attribute that we care about changes, when native validation changes, and when the view value changes (OR, whenever ngModelOptions decides to commit a value).
Currently, we really suck at re-validating stuff in the parsers/formatters pipelines, but not all of that stuff can be necessarily ported into the $validators pipeline due to needing to be run in a specific order.
I think we need a better refactoring, because this isn't quite enough. It SHOULD be a very simple thing to do, but we've overengineered the form controls so much that it's become quite a pain to manage.
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.
On blink-dev there's been a thread lately about implementing
reportValidity()
--- distinct fromcheckValidity()
.It's not clear whether there's enough vendor interest to implement that, but from my perspective, it's a model which makes good sense, and drastically simplifies things (if applied to Angular).
If we separate reporting validity (adding classes, rendering widgets, and so forth) and testing for validity, we have fewer knots and things to worry about breaking in the forms component.
Obviously, these aren't the only two things that need to happen, we also need to decide on a view value and model value, so I guess that would be a
reportValue
stage.I think it might be worth thinking about how we can organize this better so that there is less difficulty maintaining and improving on this in its current state.
@IgorMinar (don't read this now, but maybe on monday), what would you think about streamlining this a bit? Since there are three operations happening here, I think they should definitely not be mixed up together, they should be distinct and simpler. The way things are right now, we are crossing the streams and it becomes difficult to fix these issues without hacks.
So, my proposal is, separating this all into
test validity
,report validity
, andreport value
--- and run each operation as necessary (for instance, testing for validity on input and digest, reporting validity and reporting values at the whim of some simpler version ofngModelOptions
)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.
@caitp I couldn't understand from your comments if there is a specific use case that you think is not covered here, or if you only think that an additional refactor is required for the form validation process. An example would probably be very helpful.
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.
Part of the problem is when we want to re-validate when an interpolated attribute pertinent to a validator changes. We can't do this currently without jumping through hoops, because basically all we can do is
$setViewValue()
again, and that will be thrown away due to the value not changing.The fact that setViewValue is tied so closely to validation and committing the view value is a problem. We have multiple operations happening here, and it's not really possible to run any of them independently without adding serious hacks, and quite likely breaking things. We're "crossing the streams", and badness and hacks ensue, this is not good.
This is, in my view, a poorly designed system which has been hacked together carelessly, and we really need to put some serious thought into how this can work better.
All of these operations need to be able to happen independently, without side-effects, so that we can cover all of these use cases:
There are certainly other cases which are missing here. But the solution to these problems is not to pile on more hacks. It's gotten to the point where it's crazy, and I don't think we should keep it that way.
I'll need to hear what Igor thinks about this, because I'm guessing he would rather keep it as is, but I don't think we're going to stop fixing bugs in 1.x in the near future, and I'm pretty sure that the current forms design is just going to keep creating new issues which are impossible to fix without hacks. Combining the three operations into one is just making a mess of things, and it's a disaster
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.
To put this another way, the model we had previously was much simpler, we were still mixing different operations, but not as badly, and it would have been much easier to fix these use cases which are broken in 1.3. But now that we've got this poorly designed schlop which combines too many things, it becomes extremely difficult to fix any problem with one operation without side effects or blockage from another operation, because they're so tied together.
This is not a workable system, and I think we need to fix this, or else just throw away ngModelOptions entirely.
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 has always been the case regardless of
ngModelOptions
and it has now made possible with the use ofctrl.$validate()
, you can do it any time you like without changing the value and we are already doing it, for example, when validator definitions change.The current implementation supports all of those use cases, and I'm sorry but I really don't think it is poorly designed and certainly not made out of hacks. Refactoring is always a good idea with code which changed so much in so little time, obviously, but I have to disagree about he rest...
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 objectively a poor design.
We have multiple operations happening, and it is not currently possible for them to happen independently. For a number of these use cases, we need them to happen independently.
In order for them to happen independently, we have to introduce hacks to get around restrictions introduced by other parts of the system, which in turn break yet other parts of the system.
There is no way for this to work successfully in the long run, we need to do a better job of this.
Whether we actually do fix this or not, that depends on priorities set out by other people. However at the moment, this is complete and utter nonsense, it simply does not work.
It's not that the use-cases of ngModelOptions are bad or invalid, I'm not saying that. However the execution of ngModelOptions and the validators pipeline currently cause a lot of problems. The original system had its share of problems too, but it was more manageable due to not having these extra two hacks piled on.
We can (and arguably should) do this better, but I think we should wait and see what other people think before trying to come up with a better way to do this.
I admittedly didn't offer many thoughts when ngModelOptions and the validator pipelines were being reviewed, and it was less clear what the problems were at the time, but it's become clearer to me now that we are mixing up too much functionality which needs to be performed independently under a number of circumstances, and there's no good way to make this work without adding hacks like the
revalidate
option. The solution here removes one hack, but it replaces the hack with another restriction which will block similar use cases. This is not workable, this is not good, we need to do better, and we need to actually think about what we're putting together. Angular isn't really a toy project, people use this library, so we should put some actual thought into its development and avoid releasing stuff which is hacked together in this way.I apologize if I sound too critical right now, I wouldn't have objected during review of ngModelOptions because these problems weren't obvious to me at the time. I just think we should learn from these mistakes and not ship a pile of hacks when 1.3 is released. But whether it's a priority to fix this or not remains to be seen. There are a lot of areas which need to be refactored, and some of them simply won't be due to complexity and time constraints, but maybe the forms component is important enough that it can be corrected.
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.
Not really --- If a validation parameter changes, we can A) run
$validate()
--- which will not run parsers or formatters (and due to its design, not all validators can necessarily be stuck in the $validators pipeline), or we can run$setViewValue()
, which will have problems due to being so thoroughly tied to thengModelOptions
system, and introducing undesirable side-effects.Needless to say, this is not good, either for users or maintainers of the library. We need to do this better. At least, that's what I 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.
When do you have to do validation in parsers/formatters instead of validators?