Reputation: 1094
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?
Upvotes: 11
Views: 16118
Reputation: 10115
Angular appears to now support ng-min
and ng-max
out of the box without the necessity of writing your own directives. See this Fiddle that is using Angular 1.4.2.
Upvotes: 2
Reputation: 23191
i have face the same problem. got success by using this directive :
angular.module('tech').directive('maximum', ['$parse',
function($parse) {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ctrl) {
if (!ctrl) return;
attrs.maximum = true;
var checkMax = function(n) {
if (!n) return;
var actualValue = ctrl.$viewValue;
var maxValue = attrs.maximum;
if (parseInt(actualValue) > parseInt(maxValue)) {
ctrl.$setValidity('maximum', false);
} else {
ctrl.$setValidity('maximum', true);
}
};
scope.$watch(attrs.ngModel, checkMax);
//attrs.$observe('ngModel', remind);
attrs.$observe('maximum', checkMax);
}
}
}
]);
i got this solution from this website. for entire code you can go for this website
Upvotes: -1
Reputation: 13479
I also wrote a custom directive for it:
.directive('validateRange', ['$parse', function($parse) {
function link($scope, $element, $attrs, ngModel) {
var attrRange, range = [];
function validate(value) {
var validMin = true, validMax = true;
if (typeof range[0] === 'number') {
ngModel.$setValidity('min', value >= range[0]);
validMin = value >= range[0];
}
if (typeof range[1] === 'number') {
ngModel.$setValidity('max', value <= range[1]);
validMax = value <= range[1];
}
return validMin && validMax ? value : undefined;
}
attrRange = $attrs.validateRange.split(/,/);
range[0] = $parse(attrRange[0] || '')($scope);
range[1] = $parse(attrRange[1] || '')($scope);
$scope.$watchCollection('[' + $attrs.validateRange + ']', function(values) {
range = values;
validate(ngModel.$viewValue);
});
ngModel.$parsers.unshift(validate);
ngModel.$formatters.unshift(validate);
}
return {
link: link,
require: 'ngModel'
};
}]);
Example use:
<form name="myform" ng-init="minvalue=0;value=1;maxvalue=2">
Min Value:
<input type="number" name="minvalue" required
data-validate-range="0,value"
ng-model="minvalue">
Value:
<input type="number" name="value" required
data-validate-range="minvalue,maxvalue"
ng-model="value">
Max Value:
<input type="number" name="maxvalue" required
data-validate-range="value,false"
ng-model="maxvalue">
<pre>
myform.minvalue.$error {{ myform.minvalue.$error }}
myform.value.$error {{ myform.value.$error }}
myform.maxvalue.$error {{ myform.maxvalue.$error }}
</pre>
</form>
Upvotes: 0
Reputation: 14400
I wrote directives to fill the gap, ng-min and ng-max:
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']);
Upvotes: 22
Reputation: 364677
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
.
Upvotes: 9