Angular.js: View value not updated after $parsers run when allowInvalid: true

Created on 19 Nov 2014  路  4Comments  路  Source: angular/angular.js

When creating a form that has the setting allowInvalid: true I noticed that I was getting false positives for ng-minlength validation. I have a directive that adds a parser that filters out invalid characters that the user may try to input. In the example below '!' is an invalid character. If the user types in 'a!' the view is updated to just 'a' but minlength=2 returns true.

This happening because this.$$parseAndValidate sets the viewValue variable before the parsers run and never updates it. This cause the original viewValue to be passed to the validators. So the minlength validator sees 'a!' instead of the current value of 'a'.

I was able to correct this behavior by updating the first line of the parsers loop to

modelValue = viewValue = ctrl.$parsers[i](modelValue);

This keeps the viewValue variable in sync but I'm unclear what side effects this might cause. Any advice is appreciated.

I'm using v1.3.0-rc.1 but I see the same behavior in 1.3.3 which is what I used for the fiddle.

Here is a example of this behavior.
http://jsfiddle.net/bq9r7b98/

forms regression bug

Most helpful comment

BTW, I'd recommend also invoking ngModelCtrl.$commitViewValue() in such parsers so that the value will be committed even if ng-model-options was used to debounce or update on some trigger.

ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$commitViewValue();
ngModelCtrl.$render();

All 4 comments

Angular is not included in your jsfiddle. Can you please fix it?

It looks like the check inside $setViewValue is assuming that ngModelOptions is only used for debouncing / triggering viewValue commits, but since we added allowInvalid this doesn't work anymore.

However, $parsers are not designed to update the viewValue, and they shouldn't do that automatically, so we cannot use the fix you provided.

In the meantime you should be able to get your result by adding $commitViewValue after $setViewValue.

Sorry about that. Here is the correct version of the fiddle.

http://jsfiddle.net/bq9r7b98/4/

Can you help me understand why $parsers shouldn't change the view value? If there is a better solution for blocking the user from inserting certain characters into an input I would like to update my code. I've used this pattern for awhile but it does seem to create a lot of overhead.

I'll try adding $commitViewValue in the meantime.

Thanks

Can you help me understand why $parsers shouldn't change the view value?

It's a design decision. They were previously overloaded with validation, but this was changed, too. So we shouldn't put anything into core that guarantees updatingthe viewValue when parsing simply because it would mix concerns, but you are of course free to do it, simply because there is currently no better way. In the future, there will maybe be a better way to do it.

BTW, I'd recommend also invoking ngModelCtrl.$commitViewValue() in such parsers so that the value will be committed even if ng-model-options was used to debounce or update on some trigger.

ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$commitViewValue();
ngModelCtrl.$render();
Was this page helpful?
0 / 5 - 0 ratings