I have a simple html form containing regular text input. ng-minlength
, ng-maxlength
and ng-pattern
angular built-in form input directives are set on the input.
Problem: ng-pattern
check is applied before the length check by ng-minlength
and ng-maxlength
.
Question: how can I change the default check order: i.e. first check for the length, then apply pattern check?
Example:
<body ng-app>
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" ng-minlength="3" ng-maxlength="16" ng-pattern="/^\w+$/"/>
<div ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.pattern">Pattern error</span>
<span ng-show="myForm.name.$error.minlength || myForm.name.$error.maxlength">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
Current behavior:
- enter "#" - see "Pattern error"
- enter "###" - see "Pattern error"
Desired behavior:
- enter "#" - see "Length error"
- enter "###" - see "Pattern error"
FYI, related jsfiddle.
Thanks in advance.
I searched in angular code why this behavior. Then in the function 'textInputType' that it's the specific function that handles text inputs for the angular 'input' directive I found this at the end of this function, where we can see three blocks of code.
So, no matter if you change the declaration order of your ng-* attributes in the html input element you will always get same result but if you change the order of the blocks, I mean, put the min length validator block before pattern validator block you will have the result that you expect.
This is a solution for your problem but you have to make a litte change in angular code and I don't know if you really like this. But you got a very common situation where order of the declaration of validation concepts matters, so, something more must be done to handle this. Thanks
Write your own directive:
Then in your HTML, include the app and use the directive:
The directive uses my-minlength, my-maxlength, and my-pattern for the three values. If length fails, that will trip first. If not, then pattern will show as error if it doesn't match. Consider renaming this directive if you want to use it other places besides name as minlength, maxlength, and pattern can be passed to it via attributes. If they are left off, they will be ignored.
See jsfiddle: http://jsfiddle.net/4zpxk/6/
If you use ng-messages you should be able to set the order via the order of ng-message elements, e.g:
Also the docs on this: https://docs.angularjs.org/api/ngMessages/directive/ngMessages
You cannot change the default check order unfortunately.
One solution is to write a custom validator, not that difficult. Based on this answer, I came up with this code (fiddle)
Usage: There is an array of validation functions in the scope, they get passed to our custom directive
"validators"
as:A validator function would look like (e.g. for the
minlength
constraint):Important points are: it takes the value and the
ngModel
as arguments, performs the test (herevalue.length >= 3
) and callsngModel.$setValidity()
as appropriate.The directive registers the given functions with
ngModel.$parsers
:Many details can be tweaked and improved, but the outline works (again link to fiddle). Now the order of validation is explicitly set by the order of the validator functions in the
nameValidators
array.i just changed the order of your directives, pattern first
EDIT: uuum, tested your fiddel without changes and it shows your desired behavior ... directives are compiled by priority, bbut i don't know how to set angulars directives priority ... sorry, should have tested this first