自定义表单验证指令来比较两个字段

时间:2014-01-07 21:54:45

标签: angularjs angularjs-directive

我是一个有角度的新手,我在角度形式验证指令的工作方式上遇到了绊脚石。

我知道我可以很容易地将指令添加到各个字段,但我正在尝试添加一个验证,它将比较两个表单字段(两者都是模型的元素)。

这是一个表单框架:

<form name="edit_form" >
  <input name="min" type="number" ng-model="field.min"/>
  <input name="max" type="number" ng-model="field.max"/>
</form>

<div class="error" ng-show="edit_form.min.$dirty || edit_form.max.$dirty">
  <small class="error" ng-show="(what goes here?)">
    Min cannot exceed max
  </small>
</div>

简而言之,我想编写一个指令并使用它来显示/隐藏此small.error,如果minmax都有值min > max。如何访问一个指令中的两个字段?指令是否适合这项工作?

6 个答案:

答案 0 :(得分:76)

您不需要任何指令。只需分配&#34; min&#34;最大值到最小值。像:

<input name="min" type="number" ng-model="field.min"/>
<input name="max" type="number" ng-model="field.max" min=" {{ field.min }}"/>

您不需要任何自定义。
更多:您可以min=" {{ field.min + 1}}"

答案 1 :(得分:57)

许多给猫皮肤的方法。

PLUNKER

app.directive('lowerThan', [
  function() {

    var link = function($scope, $element, $attrs, ctrl) {

      var validate = function(viewValue) {
        var comparisonModel = $attrs.lowerThan;

        if(!viewValue || !comparisonModel){
          // It's valid because we have nothing to compare against
          ctrl.$setValidity('lowerThan', true);
        }

        // It's valid if model is lower than the model we're comparing against
        ctrl.$setValidity('lowerThan', parseInt(viewValue, 10) < parseInt(comparisonModel, 10) );
        return viewValue;
      };

      ctrl.$parsers.unshift(validate);
      ctrl.$formatters.push(validate);

      $attrs.$observe('lowerThan', function(comparisonModel){
        // Whenever the comparison model changes we'll re-validate
        return validate(ctrl.$viewValue);
      });

    };

    return {
      require: 'ngModel',
      link: link
    };

  }
]);

用法:

<input name="min" type="number" ng-model="field.min" lower-than="{{field.max}}" />
<span class="error" ng-show="form.min.$error.lowerThan">
  Min cannot exceed max.
</span>

答案 2 :(得分:5)

简单的比较会适合你吗?

<small class="error" ng-show="field.min > field.max">

如果您的案例就是这样,我认为指令会有些过分。如果您对包含应用程序逻辑的视图感到不舒服,可以将其导出到控制器的函数中:

$scope.isMinMaxInalid = function() {
    return $scope.field.min > $scope.field.max;
};

模板:

<small class="error" ng-show="isMinMaxInalid()">

答案 3 :(得分:2)

对我来说,除了反馈信息之外,我还需要将该字段定义为无效,以防止提交。所以我收集了一些方法,比如@thestewie方法,使用视图配置来收集日期比较的解决方案。我希望可以汇总所提出的解决方案。

代码位于PLUNKER

angular.module('MyApp')
    .directive('thisEarlierThan', function () {
        return {
            require: 'ngModel',
            restrict: 'A',
            link: function (scope, elem, attrs, ctrl) {
                var startDate,
                    endDate;

                scope.$watch(attrs.ngModel, function (newVal, oldVal, scope) {
                    startDate = newVal;
                    check();
                });

                scope.$watch(attrs.thisEarlierThan, function (newVal, oldVal, scope) {
                    endDate = newVal;
                    check();
                });

                var check = function () {
                    if (typeof startDate === 'undefined' || typeof endDate === 'undefined') {
                        return;
                    }

                    if (!validate(startDate)) {
                        startDate = new Date(startDate);
                        if (!validate(startDate)) {
                            return;
                        }
                    }

                    if (!validate(endDate)) {
                        endDate = new Date(endDate);
                        if (!validate(endDate)) {
                            return;
                        }
                    }

                    if (startDate < endDate) {
                        ctrl.$setValidity('thisEarlierThan', true);
                    }
                    else {
                        ctrl.$setValidity('thisEarlierThan', false);
                    }

                    return;
                };

                var validate = function (date) {
                    if (Object.prototype.toString.call(date) === '[object Date]') {
                        if (isNaN(date.getTime())) {
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                      return false;
                    }
                };
            }
        };
    })
;

答案 4 :(得分:2)

我的指令版本:

module.directive('greaterThan', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attributes, ngModelController) {
            var otherValue;

            scope.$watch(attributes.greaterThan, function (value) {
                otherValue = value;

                ngModelController.$validate();
            });

            ngModelController.$parsers.unshift(function (viewValue) {
                ngModelController.$setValidity('greaterThan', !viewValue || !otherValue || viewValue > otherValue);

                return viewValue;
            });
        }
    };
});

答案 5 :(得分:0)

您可以查看https://github.com/nelsonomuto/angular-ui-form-validation

这提供了一个预先配置了api的指令,该指令将范围及其模型公开给验证器函数。

以下是具有您特定用例的plunker:http://plnkr.co/edit/S0rBlS?p=preview

指令验证器的语法如下例所示: { errorMessage: 'Cannot contain the number one', validator: function (errorMessageElement, val, attr, element, model, modelCtrl){ /** * The model and modelCtrl(scope) are exposed in the validator function * */ return /1/.test(val) !== true;
} }