-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(ngModel): don't run parsers when executing $validate #10048
Conversation
@@ -934,6 +934,209 @@ describe('NgModelController', function() { | |||
}); | |||
}); | |||
|
|||
describe('initialization', function() { |
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 need to clean up the tests, they are way to complex and still to specific - most of them apply to calling $validate in the controller, no input needed.
@@ -2110,6 +2137,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ | |||
} | |||
var prevModelValue = ctrl.$modelValue; | |||
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid; | |||
ctrl.$$rawModelValue = modelValue; |
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 think you should clarify (with comments) what rawModelValue is, and why we need it. Otherwise it's not super clear
it looks "okay", but I'm not super happy about populating the ngModelController with more gunk, it is really confusing. So, it's okay if we have new fields on that object, but I'd appreciate if you document them (not with dgeni annotations, but just so that they're understandable to maintainers). Should get another look from Pete, too. |
I don't think we'll get it into 1.3.3 though :( |
I will add some comments; I just wanted to push it yesterday so someone can look at it before the weekend. Since it's such a "delicate" component, we shouldn't rush to get it into a release, but anyway do we even have enough material for a 1.3.3 release? Regarding the gunkiness of ngModelController, I think it's a fair trade-off: add another field instead of calling a function ($$parseAndValidate) out of context (inside $validate). |
dab714d
to
3ffeeb6
Compare
I added some comments, updated the docs, refactored the tests and fixed a bug where calling $validate would always unset parser errors. @petebacondarwin can you take a look? |
Superficially it looks good to me. I haven't tried it locally yet. |
LGTM |
Let's get this merged |
I can merge in ca. 1 hour. Should this be part of 1.3.3? |
Previously, $validate would execute the parsers to obtain a modelValue for validation. This was necessary, because a validator that is called outside of model / view update (e.g. from an observer) otherwise might only an undefined modelValue, because a previous view update has found a validation $error and set the model to undefined (as is tradition in angular) This is problematic as validators that are run immediately after the ngModelController initializes would parse the modelValue and replace the model, even though there had been no user input. The solution is to go back to an older design: the ngModelController will now internally record the $$rawModelValue. This means a model or view update will store the set / parsed modelValue regardless of validity, that is, it will never set it to undefined because of validation errors. When $validate is called, the $$rawModelValue will passed to the validators. If the validity has changed, the usual behavior is kept: if it became invalid, set the model to undefined, if valid, restore the last available modelValue - the $$rawModelValue. Additionally, $validate will only update the model when the validity changed. This is to prevent setting initially invalid models other than undefined to undefined (see angular#9063) Fixes: angular#9063 Fixes: angular#9959 Fixes: angular#9996 Fixes: angular#10025 Closes: angular#9890 Closes: angular#9913 Closes: angular#9997 Closes: angular#10048
Previously, $validate would execute the parsers to obtain a modelValue for validation. This was necessary, because a validator that is called outside of model / view update (e.g. from an observer) otherwise might only an undefined modelValue, because a previous view update has found a validation $error and set the model to undefined (as is tradition in angular) This is problematic as validators that are run immediately after the ngModelController initializes would parse the modelValue and replace the model, even though there had been no user input. The solution is to go back to an older design: the ngModelController will now internally record the $$rawModelValue. This means a model or view update will store the set / parsed modelValue regardless of validity, that is, it will never set it to undefined because of validation errors. When $validate is called, the $$rawModelValue will passed to the validators. If the validity has changed, the usual behavior is kept: if it became invalid, set the model to undefined, if valid, restore the last available modelValue - the $$rawModelValue. Additionally, $validate will only update the model when the validity changed. This is to prevent setting initially invalid models other than undefined to undefined (see angular#9063) Fixes: angular#9063 Fixes: angular#9959 Fixes: angular#9996 Fixes: angular#10025 Closes: angular#9890 Closes: angular#9913 Closes: angular#9997 Closes: angular#10048
3ffeeb6
to
e3764e3
Compare
@Narretz @petebacondarwin - Thinking about this some more, do you think it is okay that |
@shahata I think setting to |
Can we start to look at these ideas more abstractly outside of the current implementation? I have started a document here: https://docs.google.com/document/d/1-MhomULgCFOXVsqAGrI7l-cXYMYmJM4BMzgy_anC93o/edit?usp=sharing |
@Narretz the current implementation of |
@shahata With current implementation do you mean what got merged now? There are basically 3 cases:
Before this PR, $validate also included parsing (undocumented), but behavior related to the setting model to undefined did not change. Reading my last comment again, I might haven't made this clear. |
Yeah, I think we're saying the same thing :) I'm just a bit worried that ppl won't like it that |
There are some people who don't like it, but the specific behavior - setting invalid modelValues to |
Previously, $validate would execute the parsers to obtain a
modelValue for validation. This was necessary, because a validator
that is called outside of model / view update (e.g. from an observer)
otherwise might only an undefined modelValue, because a previous
view update has found a validation $error and set the model
to undefined (as is tradition in angular)
This is problematic as validators that are run immediately after
the ngModelController initializes would parse the modelValue
and replace the model, even though there had been no user input.
The solution is to go back to an older design: the ngModelController
will now internally record the $$rawModelValue. This means a model
or view update will store the set / parsed modelValue regardless
of validity, that is, it will never set it to undefined because of
validation errors.
When$validate is called, the $ $rawModelValue will passed to the
validators. If the validity has changed, the usual behavior is kept:
if it became invalid, set the model to undefined, if valid,
restore the last available modelValue - the $$rawModelValue.
Additionally, $validate will only update the model when the validity
changed. This is to prevent setting initially invalid models other
than undefined to undefined (see #9063)
Fixes: #9063
Fixes: #9959
Fixes: #9996
Fixes: #10025
Closes: #9890
Closes: #9913
Closes: #9997
Bonus: the commit which introduced parsing when validating (I actually wanted $$invalidModelValue to be removed, oh well): 9ad7d74
@caitp @petebacondarwin @lgalfaso