Angularjs Form验证一组输入

时间:2015-07-13 09:27:08

标签: angularjs validation angularjs-directive

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

在这个项目中我有这个场景:

我需要设置预付款字段,此预付款必须介于最小/最大值之间。 要设置Advance,我有三个输入文本:

  • 现金
  • 旧车价值
  • Financed Advance

这三个输入的总和是我的高级值。

所以我需要验证Advance,但我没有设置ng-model的单一输入。

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

我需要为所有这三个输入字段添加一个指令吗?或者更好的表格指令?

任何建议都将受到赞赏。

jsfiddle example

(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;
        }

    });

})();

2 个答案:

答案 0 :(得分:1)

只是为了给你(或许是其他人)另一种选择。

为简化起见,您可以使用数字输入,并将其ng-model设置为 plan.advance 。这将允许您使用最小/最大属性。如果您不想显示输入,可以将输入设置为隐藏。

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

然后您可以使用min和max的内置验证,例如:

<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 :(得分:0)

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

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