I have numerous number input fields that have min and max attribute values that depend on logic elsewhere in my AngularJS app, but when using data bindings within these attributes they are no longer validated by Angular, however, the HTML 5 validation still appears to pick them up.
var myApp = angular.module('myApp', []);
function FirstCtrl($scope) {
$scope.min = 10;
$scope.max = 20;
}
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<form name="myForm">
<input type="number" name="one" required="required"
min="10" max="20" ng-model="one" />
<input type="number" name="two" required="required"
min="{{ min }}" max="{{ max }}" ng-model="two" />
<button ng-disabled="!myForm.$valid">Submit</button>
</form>
</div>
</div>
Live version: http://jsfiddle.net/kriswillis/bPUVH/2/
As you can see, the validation is still handled fine in the HTML/CSS (Bootstrap) as both fields turn red when invalid, however, the submit button (handled by Angular) is not disabled when the second field is invalid. Also, there are no min and max properties in myForm.two.$error
as there are in myForm.one.$error
.
Can anyone see where I'm going wrong?
I wrote directives to fill the gap, ng-min and ng-max:
http://jsfiddle.net/g/s5gKC/
var app = angular.module('app', []);
function isEmpty(value) {
return angular.isUndefined(value) || value === '' || value === null || value !== value;
}
app.directive('ngMin', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
scope.$watch(attr.ngMin, function(){
ctrl.$setViewValue(ctrl.$viewValue);
});
var minValidator = function(value) {
var min = scope.$eval(attr.ngMin) || 0;
if (!isEmpty(value) && value < min) {
ctrl.$setValidity('ngMin', false);
return undefined;
} else {
ctrl.$setValidity('ngMin', true);
return value;
}
};
ctrl.$parsers.push(minValidator);
ctrl.$formatters.push(minValidator);
}
};
});
app.directive('ngMax', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
scope.$watch(attr.ngMax, function(){
ctrl.$setViewValue(ctrl.$viewValue);
});
var maxValidator = function(value) {
var max = scope.$eval(attr.ngMax) || Infinity;
if (!isEmpty(value) && value > max) {
ctrl.$setValidity('ngMax', false);
return undefined;
} else {
ctrl.$setValidity('ngMax', true);
return value;
}
};
ctrl.$parsers.push(maxValidator);
ctrl.$formatters.push(maxValidator);
}
};
});
angular.bootstrap(document.body, ['app']);
Apparently we can't use {{}}s (i.e., interpolation) for the min
and max
fields. I looked at the source code and I found the following:
if (attr.min) {
var min = parseFloat(attr.min);
$interpolate
is not called, just parseFloat
, so you'll need to specify a string that looks like a number for min
and max
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With