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

Decouple $parsers / $formatters and validation #6740

Closed

Description

@Narretz

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)

Activity

  1. lrlopez commented on Apr 6, 2014

    @lrlopez
    Contributor

    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?

  2. matsko commented on Apr 28, 2014

    @matsko
    Contributor

    @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.

  3. matsko commented on May 7, 2014

    @matsko
    Contributor

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

  4. Narretz commented on May 7, 2014

    @Narretz
    ContributorAuthor

    cool, will check out

  5. smashercosmo commented on Jun 14, 2014

    @smashercosmo

    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.

  6. matsko commented on Jun 16, 2014

    @matsko
    Contributor

    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.

  7. Narretz commented on Jun 16, 2014

    @Narretz
    ContributorAuthor

    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.

  8. smashercosmo commented on Jun 16, 2014

    @smashercosmo

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

  9. matsko commented on Jun 16, 2014

    @matsko
    Contributor

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

  10. smashercosmo commented on Jun 16, 2014

    @smashercosmo

    @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.

  11. matsko commented on Jun 16, 2014

    @matsko
    Contributor

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

  12. Narretz commented on Jun 16, 2014

    @Narretz
    ContributorAuthor

    @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.

  13. added this to the milestone on Jul 11, 2014
  14. IgorMinar commented on Oct 1, 2014

    @IgorMinar
    Contributor

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

  15. changed the title [-](2.0?) Decouple $parsers / $formatters and validation[/-] [+]Decouple $parsers / $formatters and validation[/+] on Oct 1, 2014
  16. Narretz commented on Oct 1, 2014

    @Narretz
    ContributorAuthor

    Yep, I think it's done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions