Angular - 依赖字段验证

Posted

技术标签:

【中文标题】Angular - 依赖字段验证【英文标题】:Angular - Dependent Field Validation 【发布时间】:2016-05-27 15:29:22 【问题描述】:

我遇到了问题。我正在尝试为我的表单创建一个验证指令。我的验证过程有点复杂。我有 4 个选择(下拉菜单)。第一个团队(用户和代理)有 2 个下拉菜单,第二个团队也有 2 个下拉菜单。

我的验证指令需要执行以下操作:

    已选择用户一线队,但未选择副一线队(需要副一线队)

    选择了副第一团队,但不是用户第一团队(需要用户第一团队)

    选择了用户二队但不是副二队(需要副二队) 选择了副二队,但不是用户二队(需要用户二队) 没有为第一或第二团队选择用户或代理人(至少需要一个用户或代理人)

我的 html 看起来像这样:

        <div class="row" ng-form="reportForm" ng-model="report" require-users>                
            <!-- User First Team -->
            <div class="col-sm-3 col-xs-6">
                <div class="form-group">
                    <label>User First Team</label>
                    <!-- Dropdown User First Team -->
                    <select ng-form="reportForm.userFirst" 
                            ng-model="report.userFirst" 
                            ng-options="user.Name for user in users track by user.Id" 
                            class="form-control">
                        <option></option>
                    </select>

                    <!-- Error Messages-->
                    <div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
                        <!-- Message required -->
                        <div ng-message="requireUserFirst">
                            <small>A User for the first team is required.</small>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Deputy First Team -->
            <div class="col-sm-3 col-xs-6">
                <div class="form-group">
                    <label>Deputy First Team</label>
                    <!-- Dropdown Deputy First Team -->
                    <select ng-form="reportForm.deputyFirst" 
                            ng-model="report.deputyFirst" 
                            ng-options="user.Name for user in users track by user.Id" 
                            class="form-control">
                        <option></option>
                    </select>

                     <!-- Error messages -->
                    <div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
                        <!-- Message required -->
                        <div ng-message="requireDeputyFirst">
                            <small>A Deputy for the first team is required.</small>
                        </div>
                    </div>
                </div>
            </div>
            <!-- User Second Team -->
            <div class="col-sm-3 col-xs-6">
                <div class="form-group">
                    <label>User Second Team</label>
                    <!-- Dropdown User Second Team -->
                    <select ng-form="reportForm.userSecond" 
                            ng-model="report.userSecond" 
                            ng-options="user.Name for user in users track by user.Id" 
                            class="form-control">
                        <option></option>
                    </select>

                     <!-- Error messages -->
                    <div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
                       <!-- Message required -->
                        <div ng-message="requireUserSecond">
                            <small>A User for the second team is required.</small>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Deputy Second Team -->
            <div class="col-sm-3 col-xs-6">
                <div class="form-group">
                    <label>Deputy Second Team</label>
                    <!-- Dropdown Deputy Second Team -->
                    <select ng-form="reportForm.deputySecond" 
                            ng-model="report.deputySecond" 
                            ng-options="user.Name for user in users track by user.Id" 
                            class="form-control">
                        <option></option>
                    </select>

                     <!-- Error messages -->
                    <div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
                        <!-- Message required -->
                        <div ng-message="requireDeputySecond">
                            <small>A Deputy for the second team is required.</small>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Error messages -->
            <div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert" class="col-xs-12">
                <!-- Message missing user and deputy -->
                <div ng-message="requireAll">
                    <small><strong>At least one user and deputy is needed.</strong></small>
                </div>
            </div>
  </div>

我的指令在这里:

app.directive('requireUsers', function () 
    return 
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ngModel) 
            scope.$watch(function () 
                return ngModel.$modelValue;
            , function (model, oldModel) 
                if (model != oldModel) 

                    if (model.userFirst == null && model.deputyFirst == null && model.userSecond == null && model.deputySecond == null) 
                        ngModel.$setValidity('requireAll', false);
                     else 
                        ngModel.$setValidity('requireAll', true);
                    

                    if ((model.userFirst == undefined || model.userFirst == null) && model.deputyFirst != null) 
                        ngModel.$setValidity('requireUserFirst', false);
                     else 
                        ngModel.$setValidity('requireUserFirst', true);
                    

                    if ((model.deputyFirst == undefined || model.deputyFirst == null) && model.userFirst != null) 
                        ngModel.$setValidity('requireDeputyFirst', false);
                     else 
                        ngModel.$setValidity('requireDeputyFirst', true);
                    

                    if ((model.userSecond == undefined || model.userSecond == null) && model.deputySecond != null) 
                        ngModel.$setValidity('requireUserSecond', true);
                     else 
                        ngModel.$setValidity('requireUserSecond', true);
                    

                    if ((model.deputySecond == undefined || model.deputySecond == null) && model.userSecond != null) 
                        ngModel.$setValidity('requireDeputySecond', false);
                     else 
                        ngModel.$setValidity('requireDeputySecond', true);
                    
                
            );
        
    ;
);

问题是观察者只有在指令被初始化时才起作用。因此,当我更改值时,验证过程不会开始。

更新报告控制器:

angular.module('ReportTool')
    .controller('ReportController', ['$scope', 'Report', 'User', function ($scope, Report, User) 
        var _this = this;

        // Load all Teammembers (API Call in Service)
        User.query().then(function (success) 
            _this.users= success.data;
        , function (error) 
            console.log('Users could not be loaded.');
        );            

        // Save report
        this.save = function () 
            if (_this.report != null) 
                // create report
                Report.post(_this.report).then(function (success) 
                    console.log('Report created.');
                , function (error) 
                    console.log('Report could not be created.');
             else 
                console.log('Report is null.');
            
        ;
    ]);

【问题讨论】:

你可以添加你的控制器或者做一个 plunker 吗? 可能,您应该对每个 INPUTSELECT 使用指令 requireUsers @dendimiiii 你到底需要什么控制器? @StepanKasyanenko 如果这样做,我将无法读取其他用户或代表,因为每个 SELECT 元素的 ng-model 都不同。 自己动手做一个 :) 【参考方案1】:

在这种情况下,您需要为每个检查编写一个指令,例如 requireUsers

我建议使用指令use-form-error。 轻松创建自定义检查。

jsfiddle 上的实时示例。

angular.module('ExampleApp', ['use', 'ngMessages'])
  .controller('ExampleController', function($scope) 

  );
.errors 
  color: maroon
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<div ng-app="ExampleApp">
  <div ng-controller="ExampleController">

    <form name="myForm">
      <label>User first:</label>
      <input type="text" ng-model="userFirst" name="userFirst" use-form-error="requireUserFirst" use-error-expression="!userFirst && deputyFirst" />
      <br>
      <label>Deputy first:</label>
      <input type="text" ng-model="deputyFirst" name="deputyFirst" use-form-error="requireDeputyFirst" use-error-expression="userFirst && !deputyFirst"/>
      <br>
      <hr>

      <label>User second:</label>
      <input type="text" ng-model="userSecond" name="userSecond" />
      <br>
      <label>Deputy second:</label>
      <input type="text" ng-model="deputySecond" name="deputySecond" />
      <br>

      <div use-form-error="requireAll" use-error-expression="!userFirst && !deputyFirst && !userSecond && !deputySecond" use-error-input="myForm"> </div>
      <div ng-messages="myForm.$error" class="errors">
        <div ng-message="requireAll">At least one user and deputy is needed.</div>
      </div>
      <div ng-messages="myForm.userFirst.$error" class="errors">
        <div ng-message="requireUserFirst">A User for the first team is required.</div>
      </div>
      <div ng-messages="myForm.deputyFirst.$error" class="errors">
        <div ng-message="requireDeputyFirst">A Deputy for the first team is required.</div>
      </div>
    </form>

  </div>
</div>

【讨论】:

没有办法只用一个指令吗?就像我对 require-users 指令所做的那样?将指令放在一个元素中而不是在每个选择中对我来说会容易得多。你知道我的意思吗? 我添加了另一个答案。请检查。【参考方案2】:

您可以简单地将变量传递到您的directive。然后检查一下。

jsfiddle 上的实时示例。

angular.module('ExampleApp', ['ngMessages'])
  .controller('ExampleController', function($scope) 

  )
  .directive('requireUsers', function() 
    return 
      restrict: 'A',
      require: 'form',
      scope: 
        userFirst: "=",
        deputyFirst: "=",
        userSecond: "=",
        deputySecond: "=",
      ,
      link: function(scope, elem, attr, ngModel) 
        function changeValue(model, oldModel) 
          if (!scope.userFirst && !scope.deputyFirst && !scope.userSecond && !scope.deputySecond) 
            ngModel.$setValidity('requireAll', false);
           else 
            ngModel.$setValidity('requireAll', true);
          

          if (!scope.userFirst && scope.deputyFirst) 
            ngModel.$setValidity('requireUserFirst', false);
           else 
            ngModel.$setValidity('requireUserFirst', true);
          

          if (!scope.deputyFirst && scope.userFirst) 
            ngModel.$setValidity('requireDeputyFirst', false);
           else 
            ngModel.$setValidity('requireDeputyFirst', true);
          

          if (!scope.userSecond && scope.deputySecond) 
            ngModel.$setValidity('requireUserSecond', false);
           else 
            ngModel.$setValidity('requireUserSecond', true);
          

          if (!scope.deputySecond && scope.userSecond) 
            ngModel.$setValidity('requireDeputySecond', false);
           else 
            ngModel.$setValidity('requireDeputySecond', true);
          
        
        scope.$watch('userFirst', changeValue);
        scope.$watch('deputyFirst', changeValue);
        scope.$watch('userSecond', changeValue);
        scope.$watch('deputySecond', changeValue);
      
    ;
  );;
.errors 
  color: maroon
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<div ng-app="ExampleApp">
  <div ng-controller="ExampleController">

    <form name="myForm" require-users user-first="userFirst" deputy-first="deputyFirst" user-second="userSecond" deputy-second="deputySecond">
      <label>User first:</label>
      <input type="text" ng-model="userFirst" name="userFirst" />
      <br>
      <label>Deputy first:</label>
      <input type="text" ng-model="deputyFirst" name="deputyFirst" />
      <br>
      <hr>

      <label>User second:</label>
      <input type="text" ng-model="userSecond" name="userSecond" />
      <br>
      <label>Deputy second:</label>
      <input type="text" ng-model="deputySecond" name="deputySecond" />
      <br>


      <div ng-messages="myForm.$error" class="errors">
        <div ng-message="requireAll">At least one user and deputy is needed.</div>
        <div ng-message="requireUserFirst">A User for the first team is required.</div>
        <div ng-message="requireDeputyFirst">A Deputy for the first team is required.</div>
        <div ng-message="requireUserSecond">A User for the second team is required.</div>
        <div ng-message="requireDeputySecond">A Deputy for the second team is required.</div>
      </div>
    </form>

  </div>
</div>

【讨论】:

对不起,如果我很挑剔,但我认为这个解决方案并不干净,因为你必须“连接”模型。我相信有更好的解决方案。也许你知道为什么我的观察者只执行一次,即使我改变了模型?感谢您的帮助和时间! 你的观察者只为了改变你的FORM值!在代码 return ngModel.$modelValue 中,您告诉监视 form 的更改值。您的 form 值与 inputselect 中的 ng-model 不同。 我正在更新 jsfiddle。它现在没有“连接”模型。 为什么采用这种形式?我写了 ng-model="report" 不应该把它作为指令中的 ngModel 吗? 您在标签
中使用了directive require-users。然后使用ngModel。指令选择 FORM,因为您在表单中初始化指令。你的ng-model='report' 没有指令require-users。更多关于directive的细节。

以上是关于Angular - 依赖字段验证的主要内容,如果未能解决你的问题,请参考以下文章

多个字段的Angular 4表单验证

密码和确认密码字段验证 angular2 反应形式

使用 Angular 和 jquery 验证输入字段?

Angular 5 - 表单验证电子邮件

触发 Angular 表单提交中所有字段的验证

Angular 4 表单验证和错误消息