Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Decouple $parsers / $formatters and validation #6740

Closed
Narretz opened this issue Mar 18, 2014 · 14 comments
Closed

Decouple $parsers / $formatters and validation #6740

Narretz opened this issue Mar 18, 2014 · 14 comments

Comments

@Narretz
Copy link
Contributor

Narretz commented Mar 18, 2014

This is just quick n dirty, otherwise I'll never open this issue.
Note: This is not only a suggestion for 2.0, I just don't know how much effort it takes to include it into 1.3.x However, it should be taken into consideration for 2.0 from the start (I think).

Problem:

In #1412 it was brought up that ngModel currently does not show invalid values, say wrong.de would not show in input type="email"
This is because currently, $formatters (in this case) and $parsers handle validation. In general, every $f / $p in the chain can transform the view / model value to its liking. In most cases however it is not transformed, but validated. If a validation fails, the $f/$p returns undefined. Currently this means the following:

  • If validation fails in the $formatter chain, an ngModel won't have a viewValue
  • If validation fails in the $parsers chain, an ngModel won't have a modelValue
  • It's impossible to collect all validation errors, since the first failure shortcuts the chain

Use cases for decoupling:

  • You want to display stored data in forms, which may contain invalid values (requirements have changed, you have legacy data)
  • You want to have data in the model, regardless of validity, but store the validation errors with them

Current approaches:

In #1412, evangalen showed a way to get the invalid output: If you put a $f / $p at the end of the chain, you can pull out the 'raw' value and populate your view / model. However, this is not enough, as you may want to use the chain to transform your values. With this solution you'd have to reapply your transformations. (I don't think you can use $filters with ngModel, but please correct me if I am wrong.)

Requirements / Possible approaches:

  • A way to specify that invalid values should be used to populate $view / $model. This could happen in the form of directive attributes. The validation errors could probably be pulled out ngModel during submission if needed.
  • The $formatters / $parsers chain needs to run all items in the chain regardless of validation failure, but still log all errors, or needs to be separated from a new validator chain

Related: #3407 (manually rerun chain)
Also might be worthwhile to take into consideration before any big refactorings are made: #6416 (async form validation)

@lrlopez
Copy link
Contributor

lrlopez commented Apr 6, 2014

Just a couples of ideas:

  1. If we are going to reboot the $parsers/$formatters/validation process we could introduce nice features. What about using onion-like chains?

This way, every callback in the chain would have the chance to process the input, call the following callback and, when it returns, it would be able to process the returned value again before going back to the former callback in the chain.

All the callbacks could have the chance of propagate validation errors or just short-circuit the chain at will by not calling the following callback.

I know this is a radical departure of the current way of doings things but the feature would add a lot of flexibility. It may be worth the effort.

Note: we could add a second optional parameter to the $formatters/$parsers callbacks that would switch on the new behavior. This way we could keep backwards compatibility for the callbacks (if it is false or undefined, we would keep the old conduct).

  1. Also, as @Narretz proposed, we could flag if invalid values should be used in order to populate the view or the model. Here is where the new directive ng-model-options (feat(ngModelOptions): Model update behavior can now be customized #6945) could be used (i.e. ng-model-options="{ allowInvalidModelValues: true, allowInvalidViewValues: true }".

What do you think about these 2 suggestions?

@matsko
Copy link
Contributor

matsko commented Apr 28, 2014

@Narretz we're planning on introducing a $validators pipeline into 1.3 that is separate from $parsers/$formatters that will deal with the raw model value.

Before I read over everything here, how a look at: https://github.com/angular/angular.dart/blob/master/lib/directive/ng_model_validators.dart to see how Dart handles this.

@matsko
Copy link
Contributor

matsko commented May 7, 2014

@Narretz here is what I have so far: #7377

@Narretz
Copy link
Contributor Author

Narretz commented May 7, 2014

cool, will check out

@smashercosmo
Copy link

any updates on the issue? Because in spite of $validators pipeline introduced, we still don't have a way to keep model values regardless of validity.

@matsko
Copy link
Contributor

matsko commented Jun 16, 2014

The rule is that when one or more validations fails then the model value is not applied. Before this was up to the mercy of $parsers, but it caused some strict dependencies in terms of the ordering of parsers. Now the value in between validators doesn't change between validations. The goal is to get as many validators as possible into the new $validators pipeline.

@smashercosmo what exactly is the use case? We could have a new property on the model controller valled $invalidModelValue. Or we could have something like $rawModelValue which is there regardless of validity state. But the actual bound model value must be the perfect value that is only there if the model is valid.

@Narretz
Copy link
Contributor Author

Narretz commented Jun 16, 2014

What about an option on ngModel that sets the model value even if invalid (similar to the new model update options)?

One problem with the current behavior is that if you have an invalid model defined on the scope, it shows in the input and is defined on the scope (duh), but when you change it in the input, and it's still invalid, it's not set on the scope anymore. At least confusing.

@smashercosmo
Copy link

@matsko for example we want to warn user about incorrect fields in a form, but we don't want to prevent form submition.

@matsko
Copy link
Contributor

matsko commented Jun 16, 2014

Yes then this would fall back to ngModel to keeping the modelValue as the parsed value, but still keeping myForm.$invalid as true.

@smashercosmo
Copy link

@matsko maybe we need some kind of $warnings pipeline) that will add classes like ng-required-warning and all that $validators pipeline stuff except of writing "undefined" to the $modelValue in case of warnings.

@matsko
Copy link
Contributor

matsko commented Jun 16, 2014

Yes exactly. I was thinking of $info, but warnings would be better.

@Narretz
Copy link
Contributor Author

Narretz commented Jun 16, 2014

@smashercosmo Actually, submitting a form with invalid values works already. The form has the currently private $$invalidModelValue property, which you could set yourself to the model. But it's probably better to make this optional anyway.

@IgorMinar
Copy link
Contributor

@Narretz can we now consider this to be done and close this issue?

@IgorMinar IgorMinar changed the title (2.0?) Decouple $parsers / $formatters and validation Decouple $parsers / $formatters and validation Oct 1, 2014
@Narretz
Copy link
Contributor Author

Narretz commented Oct 1, 2014

Yep, I think it's done!

@Narretz Narretz closed this as completed Oct 1, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants