【问题标题】:min/max validations not working if values are changed later如果稍后更改值,则最小/最大验证不起作用
【发布时间】:2016-12-09 04:44:58
【问题描述】:

我有一个要求,其中一个字段的最小值取决于另一个字段中给出的输入。

<input type="number" name="minval" class="form-control" ng-model="user.minval" 
      ng-required="true">

此输入用于验证另一个字段

<input type="number" name="inputval" class="form-control" ng-model="user.inputval" 
     ng-required="true" min="{{user.minval}}">

但这没有按预期工作..如果我稍后更改“minval”,则输入不会重新验证..

我已尝试按照某些解决方案中的建议从 JS 设置 min 的初始值,但这也无济于事...

PLUNKER LINK

【问题讨论】:

  • 如果第一个输入的原始最小值变得低于第二个输入值,您希望发生什么?
  • 通过谷歌搜索,我发现了一个非常有用的 SO 帖子:stackoverflow.com/questions/15656617/…
  • 非常感谢@ForgetfulFellow
  • 我想我不需要回答你的第一条评论。链接是我所面临问题的答案。

标签: angularjs


【解决方案1】:

使用 ng-min/ng-max 指令

app.directive('ngMin', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            scope.$watch(attr.ngMin, function(){
                if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
            });

            var isEmpty = function (value) {
               return angular.isUndefined(value) || value === "" || value === null;
            }

            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(){
                if (ctrl.$isDirty) 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);
        }
    };
});

【讨论】:

  • 感谢那些伟大的工作。只有一个补充,如果您将 required-attribute 与这些指令结合使用,该字段会立即被标记为无效,这对用户来说不是很友好。您可以通过检查手表 if(ctrl.$isDirty) ... 中的字段是否脏并仅执行 setViewValue 来解决此问题。
  • @akiro 实际上我已经在代码中做到了,忘记更新答案。无论如何,感谢您的输入。
  • 说真的?,你想用手表来做那个吗?...angular-tips.com/blog/2013/08/removing-the-unneeded-watches
  • 嘿,isEmpty() 没有定义
  • 此解决方案首次出现在这里:stackoverflow.com/questions/15656617/… 请注意,Angular 现在支持 ng-min 和 ng-max,无需编写自己的指令。
【解决方案2】:

我开发了几个指令,实际上限制用户设置无效值,而不是在提供无效值时简单地抛出错误。

这些指令也不需要 ngModel(尽管我怀疑你会在没有它们的情况下使用它们),真正酷的是 如果提供了这两个设置,它会将值环绕到最小值/最大值!

我已尝试尽可能简化指令,以使我们的读者更容易理解。

这是整个事情的 JSFiddle:JSFiddle

以下是指令:

app.directive('ngMin', function($parse){
    return {
        restrict: 'A',
        link: function(scope, element, attrs){
            function validate(){
                if(element
                && element[0]
                && element[0].localName === 'input'
                && isNumber(attrs.ngMin)
                && isNumber(element[0].value)
                && parseFloat(element[0].value) < parseFloat(attrs.ngMin)){
                    if(isNumber(attrs.ngMax)){
                        element[0].value = parseFloat(attrs.ngMax);
                        if(attrs.hasOwnProperty("ngModel"))
                            $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
                    }
                    else {
                        element[0].value = parseFloat(attrs.ngMin);
                        if(attrs.hasOwnProperty("ngModel"))
                            $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
                    }
                }
            }
            scope.$watch(function(){
                return attrs.ngMin + "-" + element[0].value;
            }, function(newVal, oldVal){
                if(newVal != oldVal)
                    validate();
            });
            validate();
        }
    };
});
app.directive('ngMax', function($parse){
    return {
        restrict: 'A',
        link: function(scope, element, attrs){
            function validate(){
                if(element
                && element[0]
                && element[0].localName === 'input'
                && isNumber(attrs.ngMax)
                && isNumber(element[0].value)
                && parseFloat(element[0].value) > parseFloat(attrs.ngMax)){
                    if(isNumber(attrs.ngMin)){
                        element[0].value = parseFloat(attrs.ngMin);
                        if(attrs.hasOwnProperty("ngModel"))
                            $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
                    }
                    else {
                        element[0].value = parseFloat(attrs.ngMax);
                        if(attrs.hasOwnProperty("ngModel"))
                            $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
                    }
                }
            }
            scope.$watch(function(){
                return attrs.ngMax + "-" + element[0].value;
            }, function(newVal, oldVal){
                if(newVal != oldVal)
                    validate();
            });
            validate();
        }
    };
});

...还有,你也需要这个小辅助函数:

function isNumber(n){
    return !isNaN(parseFloat(n)) && isFinite(n);
}

要调用这些指令,只需将它们设置在type="number" 所在的输入框中:

<input ng-model="myModel" ng-min="0" ng-max="1024" />

应该这样做!

当您同时提供ngMinngMax 时,这些指令会将值环绕,因此当您的值小于ngMin 时,它将设置为ngMax,反之亦然。

如果您只提供ngMinngMax,则输入值将仅以这些值为上限。

我更喜欢这种防止错误值的方法,而不是提醒用户他们输入了错误值。

【讨论】:

    猜你喜欢
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 2015-11-10
    • 2015-04-08
    相关资源
    最近更新 更多