数据绑定数字输入的最小/最大属性时不会触发验证

时间:2013-03-27 10:27:43

标签: angularjs

我有许多数字输入字段,其最小和最大属性值取决于我的AngularJS应用程序中的其他位置的逻辑,但是当在这些属性中使用数据绑定时,它们不再由Angular验证,但是,仍然会出现HTML 5验证接他们。

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>

实时版:http://jsfiddle.net/kriswillis/bPUVH/2/

正如您所看到的,HTML / CSS(Bootstrap)中的验证仍处于正常状态,因为两个字段在无效时变为红色,但是,当第二个字段无效时,不会禁用提交按钮(由Angular处理)。此外,myForm.two.$error中没有myForm.one.$error中的最小和最大属性。

谁能看到我出错的地方?

5 个答案:

答案 0 :(得分:22)

我写了指令来填补空白,ng-min和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']);

答案 1 :(得分:9)

显然,我们无法对minmax字段使用{{}} s(即插值)。我看了source code,发现了以下内容:

if (attr.min) {
  var min = parseFloat(attr.min);

$interpolate未被调用,只是parseFloat,因此您需要指定一个类似于minmax的数字的字符串。

答案 2 :(得分:2)

Angular似乎现在支持ng-minng-max开箱即用,而无需编写自己的指令。请参阅使用Angular 1.4.2的this Fiddle

答案 3 :(得分:0)

我还为它写了一个自定义指令:

工作演示:http://plnkr.co/edit/BJ98ZR?p=preview

.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'
    };

}]);

使用示例:

<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>

答案 4 :(得分:-1)

我面临同样的问题。通过使用此指令获得成功:

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);

      }
    }
  }
]);

我从this网站获得了此解决方案。对于整个代码,您可以访问this网站