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:
Desired behavior:
FYI, related jsfiddle.
Thanks in advance.
Write your own directive:
var mod = angular.module("myApp", []);
mod.directive("nameValidation", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attrs, ngModelCtrl) {
var validate = function (value) {
var minLen = parseInt(attrs.myMinlength, 10),
maxLen = parseInt(attrs.myMaxlength, 10),
pattern = attrs.myPattern,
match = pattern.match(/^\/(.*)\/([gim]*)$/),
lenErr = false;
if (match) {
pattern = new RegExp(match[1], match[2]);
}
if (!ngModelCtrl.$isEmpty(value)) {
ngModelCtrl.$setValidity("pattern", true);
if ((minLen && value.length < minLen) || (maxLen && value.length > maxLen)) {
ngModelCtrl.$setValidity("length", false);
lenErr = true;
}
else {
ngModelCtrl.$setValidity("length", true);
lenErr = false;
}
if (!lenErr) {
if (match && !pattern.test(value)) {
ngModelCtrl.$setValidity("pattern", false);
}
else {
ngModelCtrl.$setValidity("pattern", true);
}
}
}
else {
ngModelCtrl.$setValidity("length", true);
ngModelCtrl.$setValidity("pattern", true);
}
}
ngModelCtrl.$parsers.push(validate);
ngModelCtrl.$formatters.push(validate);
}
}
});
Then in your HTML, include the app and use the directive:
<body ng-app="myApp">
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" name-validation="" my-minlength="3" my-maxlength="16" my-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.length">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
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/