Skip to content

Instantly share code, notes, and snippets.

@Narretz
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Narretz/c7f781652544f3aa3660 to your computer and use it in GitHub Desktop.
Save Narretz/c7f781652544f3aa3660 to your computer and use it in GitHub Desktop.
angular.js input validation / parsing
Currently, processing angular input processing works like this:
$viewValue -> $parsers -> $modelValue -> $validators -> $modelValue -> model on $scope
$viewValue is the value that is displayed to the user in the input
the $viewValue is run through the $parsers pipeline
each parser receives the result of the previous $parser
$parsers can theoretically completely change the $viewValue and the result is the $modelValue
$modelValue is run through the $validators collection
each validator operates on the same $modelValue
if the $modelValue is invalid, it is not commited to the $model
Problems:
if the $model value is set, there's no initial validation (the $viewValue is set)
if the $modelValue is invalid, the $model is not set, and there's no way to set in anyway
-> use case: user can login with email or username. dev uses email field for mobile keyboards, but username will always
be invalid
it's not clear what should actually be validated: the $viewValue or the $modelValue
e.g. maxlength is checking the model value, but that doesn't work for objects (e.g. type="date")
sometimes it's necessary to validate both the $viewValue and the $modelValue
but it's diffcult to decide which should use what
-> maxlength, minlength: viewValue
-> email, url: viewValue / modelValue
-> date: modelValue
use case: masked input needs to parse the viewValue and validate it after.
it's not possible to have validators depend on each other (but it's actually a good thing that all validations are collected)
Goals:
- high level API that works by enhancing inputs and providing options to the developer in directives
- low level API that exposes the individual methods of the ngModelController to the developer in a consistent way
- option to write invalid model values to the $scope
- support for asynchronous validation
- debouncing validation
- easy way for devs to work with pure or partial server side validation (i.e. submitting the form)
- seamless integration of HTML5 validators
- consistent use of $parsers / $formatters and $validators
- make it easy to customize / overwrite validators
- dependant $validators?
Current bugs / implementation problems:
- invalidating a control with $setValidity blocks all further model updates and also empties the modelValue
- HTML5 validation (number) breaks other validations, because it lives in parsers
-> it currently aborts completely when it finds the error before angular number validator kicks in
-> this causes the parser pipeline to short-circuit
-> moving it to $validators means we overreport number / required ??
- otherwise, the number validator would also run its own validation again
- calling $setViewValue does too much: sets the $viewValue, runs the $validators, sets $$invalidModelValue and $modeValue and writes the model to scope, all while aborting some of the operations in some circumstances
- it's not clear whether $parsers / $formatters should ever be able to $validate
- it's not clear when $parsers and $validators should run
Implementation notes:
- refactor the control handling to separate $setViewValue, $parse / $format, $validate and $writeModelToScope
- modeValue should always be set, only scope value should be deferred / (not) set because of validity
- three actions: checkValidity, reportValidity, setValue
- scenarios when checkValidation must run: (input and digest)
-> interpolated attribute for validator changes
-> native validation changes
-> when the viewValue (or modelValue) changes
-> when ngModelOptions decides to commit a $viewValue
-> debounced validationUpdate?
- when reportValidity must run
-> debounceModelUpdate
-> calling $setValidity
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment