AngularJS表单验证:一组输入的验证

4

使用Angular,我使用特定的指令来验证单个输入字段(例如电子邮件、用户名等)。

在这个项目中,我有如下场景:

我需要设置一个预付款字段,该预付款必须在最小/最大值之间。为了设置预付款,我有三个文本输入框:

  • 现金
  • 旧车价值
  • 融资预付款

这三个输入框的总和是我的预付款金额。

所以我需要验证预付款金额,但我没有单个输入框上设置ng-model。

检查和验证预付款金额的最佳方法是什么?

我需要向这三个输入框添加指令吗?还是更好地为表单添加指令?

非常感谢您的建议。

jsfiddle示例

(function () {
    var app = angular.module("myApp", ['ngMessages']);

    app.controller('myFormCtrl', function($scope) {
        $scope.plan = {};
        $scope.plan.advance = 0;
        $scope.plan.min_advance = 3000;   
        $scope.plan.max_advance = 6000;        

        $scope.updateAdvance = function(){
            var advance = 0;
            if ($scope.quotationAdvanceType && !isNaN($scope.plan.quotation))
                advance += $scope.plan.quotation;
            if ($scope.cashAdvanceType && !isNaN($scope.plan.cash))
                advance += $scope.plan.cash;
            if ($scope.financedAdvanceType && !isNaN($scope.plan.financed))
                advance += $scope.plan.financed;
            $scope.plan.advance = advance;
        }

    });

})();

如果你只需要确保这三个字段都有值,使用 required。如果你需要进行进一步的验证,而内置指令如 ng-pattern 不支持,请使用自定义指令。你可以使用 ngMessage(或其他指令,如 ngIf、ngShow/Hide)创建一个单一的错误反馈信息。在遇到问题时尝试一些东西并发布你的代码。 - jme11
我要发布表单的一部分。 - Zauker
@Zauker,你不应该只是将这三个字段的总和取出来,然后如果它们不在最小值和最大值之间,就将它们全部变成红色吗? - DevNebulae
@GamerNebulae 不仅仅是一个错误消息的问题。发布的代码是更复杂表单的一部分。如果表单无效,我需要隐藏或禁用其中的一部分。在示例中,我使用“myForm.$invalid”来禁用提交按钮。我也需要同样的方式来处理AdvanceValue...我需要将表单设置为无效,并设置特定的错误消息,例如myForm.advance.$error。这是可能的吗?有没有办法做到这一点?我用指令实现了这个功能,但只适用于单个输入字段。 - Zauker
@Zauker 你无法指定哪个字段足够低以便有效。当然,你知道它不能低于零(这对我来说很合理),并且它应该至少添加到最小值。10 + 20 = 30,但15 + 15也等于30。你只是不知道哪个字段不够大。 - DevNebulae
显示剩余5条评论
2个回答

2

仅提供给您(和其他人)另一个选项。

为了简化,您可以使用一个数字输入,将其ng-model设置为plan.advance。这将允许您使用min/max属性。如果您不想显示它,可以将输入设置为隐藏。

<input type="number" name="advance" ng-model="plan.advance" min="{{plan.min_advance}}" max="{{plan.max_advance}}" hidden />

您可以使用内置的最小值和最大值验证,例如:

<span ng-messages="myForm.advance.$error" role="alert">
  <span ng-message="min">Minimum not reached.</span>
  <span ng-message="max">Maximum exceeded.</span>
</span>

运行以下代码片段以查看其效果:

(function () {
    var app = angular.module("myApp", ['ngMessages']);

    app.controller('myFormCtrl', function ($scope) {
        var advance = [];
        
        $scope.plan = {};
        $scope.plan.advance = 0;
        $scope.plan.min_advance = 3000;
        $scope.plan.max_advance = 6000;

        $scope.reset = function(val) {
            $scope.plan[val] = undefined;
            $scope.updateAdvance();
        };
        
        $scope.updateAdvance = function () {
            advance = [$scope.plan.quotation, $scope.plan.cash, $scope.plan.financed];
            $scope.plan.advance = advance.reduce(function (a, b) {
                a = a ? a : 0;
                b = b ? b : 0;
                return a + b;
            }, 0);
        }

    });

})();
@import url("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css");
<script src="https://code.angularjs.org/1.3.15/angular.min.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular-messages.min.js"></script>
<div ng-app="myApp" class="container">
    <form name="myForm" ng-controller="myFormCtrl" class="form-horizontal">
        <div class="form-group" ng-class="{ 'has-error' : myForm.plan.min_advance.$invalid && myForm.plan.min_advance.$touched}">
            <label for="plan.min_advance" class="control-label col-xs-4 col-sm-2">Min Advance</label>
            <div class="col-xs-8 col-sm-10">
                <input type="number" ng-model="plan.min_advance" class="form-control" />
            </div>
        </div>
    
        <div class="form-group" ng-class="{ 'has-error' : myForm.plan.max_advance.$invalid && myForm.plan.max_advance.$touched}">
            <label for="plan.max_advance" class="control-label col-xs-4 col-sm-2">Min Advance</label>
            <div class="col-xs-8 col-sm-10">
                <input type="number" ng-model="plan.max_advance" class="form-control" />
            </div>
        </div>
        <div class="form-group" ng-class="{ 'has-error' : myForm.surname.$invalid && myForm.surname.$touched}">
            <div class="col-xs-12">
                <label for="surname" class="control-label">Surname</label>
                <input type="text" value="" name="surname" id="surname" ng-model="surname" ng-minlength="3" ng-mAXlength="20" required="required" class="form-control" />
                <span ng-messages="myForm.surname.$error" class="help-block" role="alert" ng-show="myForm.surname.$touched">
                    <span ng-message="required">You forgot to enter your surname</span>
                    <span ng-message="minlength">Surname is too short</span>
                    <span ng-message="maxlength">Surname is too long</span>
                </span>
            </div>
        </div>
        <p>Set the Advance between minimun <strong>{{plan.min_advance | currency}}</strong> and maximum <strong>{{plan.max_advance | currency}}</strong>
        </p>
        <div class="form-group">
            <label for="quotation" class="col-xs-4 col-sm-2 control-label">
                <input type="checkbox" name="quotationAdvanceType" ng-model="quotationAdvanceType" ng-change="reset('quotation')"/> Quotation:
            </label>
            <div class="col-xs-8 col-sm-10">
                <input type="number" name="quotation" ng-value="plan.quotation" ng-model="plan.quotation" ng-change="updateAdvance()" class="form-control"  ng-disabled="!quotationAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
            </div>
        </div>
        <div class="form-group">
            <label for="cash" class="col-xs-4 col-sm-2 control-label">
                <input type="checkbox" name="cashAdvanceType" ng-model="cashAdvanceType" ng-change="reset('cash')" /> Cash:
            </label>
            <div class="col-xs-8 col-sm-10">
                <input type="number" name="cash" ng-value="plan.cash" ng-model="plan.cash" ng-change="updateAdvance()" class="form-control" ng-disabled="!cashAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
            </div>
        </div>
        <div class="form-group">
            <label for="financed" class="col-xs-4 col-sm-2 control-label">  
                <input type="checkbox" name="financedAdvanceType" ng-model="financedAdvanceType" ng-change="reset('financed')" /> Financed:
            </label>
            <div class="col-xs-8 col-sm-10">
                <input type="number" name="financed" ng-value="0" ng-model="plan.financed" ng-change="updateAdvance()" class="form-control" ng-disabled="!financedAdvanceType" placeholder="{{'max '+ (plan.max_advance-plan.advance)}}" />
            </div>
        </div>
        <div ng-class="{'has-error' : myForm.advance.$invalid && (quotationAdvanceType || cashAdvanceType || financedAdvanceType) && (myForm.quotation.$dirty || myForm.cash.$dirty || myForm.financed.$dirty)}">
            <input type="number" name="advance" ng-model="plan.advance" min="{{plan.min_advance}}" max="{{plan.max_advance}}" hidden />
            <p class="help-block">Total Advance: <strong>{{plan.advance ? (plan.advance | currency) : 'none'}}</strong>
                <span ng-messages="myForm.advance.$error" role="alert" ng-show="myForm.quotation.$dirty || myForm.cash.$dirty || myForm.financed.$dirty">
                    <span ng-message="min">Minimum not reached.</span>
                    <span ng-message="max">Maximum exceeded.</span>
                </span>
            </p>
        </div>  
        <button type="submit" class="btn btn-primary" ng-disabled="myForm.$invalid">Send</button>
    </form>
</div>

你自己编写指令的方式有优势吗?我认为是有的,以下是原因:

  1. 你的指令与控制器作用域紧密耦合,所以无法在应用程序中重复使用它,并且如果将来更改其中一个作用域变量,你需要单独更新它。
  2. 你实际上正在复制框架中已存在的功能代码,这将导致开发成本更高,维护成本也会增加。

1

我用一个全新的指令解决了我的问题。 我不知道这是否是正确的方法,但它可以正常工作并且行为是正确的。

app.directive('totalAdvance', function() {
    return {
        restrict: 'E',
        require: '^form',
        link: function(scope, element, attrs, formCtrl) {
            var advanceValue = 0;
            var advanceValidator = function() {
                if (advanceValue >= attrs.min && advanceValue <= attrs.max){
                    formCtrl.$setValidity('minAdvance', true);
                    formCtrl.$setValidity('maxAdvance', true);
                    return advanceValue;
                }else if (advanceValue < attrs.min) {
                    formCtrl.$setValidity('minAdvance', false);
                    formCtrl.$setValidity('maxAdvance', true);
                    return null;
                }else if (advanceValue > attrs.max){
                    formCtrl.$setValidity('minAdvance', true);
                    formCtrl.$setValidity('maxAdvance', false);
                    return null;
                }
            };

            scope.$watch('plan.advance', function(value) {
                advanceValue = value;
                return advanceValidator();
            });
            scope.$watch('plan.min_advance', function() {
                return advanceValidator();
            });
            scope.$watch('plan.max_advance', function() {
                return advanceValidator();
            });

        }
    };
});

jsfiddle example

的英译中,保留了HTML标签和内容,不做解释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接