使用“ng-form”启用/禁用嵌套子表单的角度表单验证

Posted

技术标签:

【中文标题】使用“ng-form”启用/禁用嵌套子表单的角度表单验证【英文标题】:Enable/disable validation for angular form with nested subforms using `ng-form` 【发布时间】:2016-10-20 22:08:17 【问题描述】:

我需要基于范围变量$scope.isValidationRequired 启用/禁用ng-form="myForm" 下的Angular 表单或子表单中的所有验证规则。因此,如果isValidationRequiredfalse,则为指定字段组设置的任何验证都不会运行,结果将始终为myForm.$valid==true,否则,验证规则将照常运行。

我做了很多研究,并意识到这个功能在 Angular 中是不可用的。但是,我发现了一些附加组件或进行了一些自定义,这是可能的。

例如,我可以将附加组件 angular-conditional-validation(github 和 demo)与自定义指令 enable-validation="isValidationRequired" 一起使用。这将是完美的,除了我不能将此功能应用于ng-form 下的一组字段。我必须为每个适用的字段添加此指令。

另一种解决方案是使用 Angular $validators 管道进行自定义验证。这需要一些额外的努力,而且我没有时间,因为 sprint 快结束了,我必须在几天内给出一些结果。

如果您有任何其他建议,请发布答案。

用例:

为了阐明这一点,我将提到用例。最终用户可以用无效数据填写表单,他可以单击Save 按钮,在这种情况下,不应该触发验证规则。只有当用户点击Validate and Save 时才会触发验证规则。

解决方案:

查看最终的 plunker 代码 here。

更新:根据下面的 cmets,如果在 ng-form 下使用内部子表单,该解决方案将导致浏览器挂起。需要更多的努力来调试和解析这个发行者。如果只使用一个级别,那么它工作正常。

更新:plunker here 已更新为更通用的解决方案。现在代码将使用在ng-form 下具有子表单的表单。函数setAllInputsDirty() 检查对象是否为$$parentForm 以停止递归。此外,changeValidity() 将使用$addControl 检查对象是否为表单,然后它将调用自身来验证其子对象。到目前为止,这个函数运行良好,但它需要一些额外的优化。

【问题讨论】:

【参考方案1】:

如果验证标志被禁用,一个想法是重置摘要循环中的错误。您可以在更改时遍历表单错误并将它们一一设置为有效。

$scope.$watch(function() 
    $scope.changeValidity();
, true);

$scope.changeValidity = function() 
    if ($scope.isValidationRequired === "false") 
        for (var error in $scope.form.$error) 
            while ($scope.form.$error[error]) 
                $scope.form.$error[error][0].$setValidity(error, true);
            
        
    

这是一个小插曲:https://plnkr.co/edit/fH4vGVPa1MwljPFknYHZ

【讨论】:

我尝试访问 plunker 示例,但收到错误“无法连接到任何应用程序实例。”。这是一个全球性问题吗? 听起来 plunkr 暂时停了下来。现在它对我有用。 哇!非常感谢。一个小问题。如果验证被关闭,并且有验证错误,然后重新打开,验证规则不会被触发。我试图研究解决方案,但没有找到快速修复它的方法。看来我必须set all form fields to dirty 但也不工作。我还找到了this,但需要很长时间才能消化。请帮忙。 好吧,看起来 Plunkr 又宕机了,所以我不能展示这个,但我认为你应该能够遍历表单并调用 $validate。我会在 Plunkr 备份时发布一个示例。 天哪!有效。现在检查它,this is your updated plunker code。能否请您确保此代码适用于生产,如果您有任何反馈。非常感谢。【参考方案2】:

这是防止无限循环和无限递归的更新答案。此外,代码依赖于已知的根形式,可以稍作调整以使其更通用。

参考:Pixelastic blog 和 Larry's answer Plunker:https://plnkr.co/edit/ycPmYDSg6da10KdoNCiM?p=preview 更新:代码改进使其适用于每个子表单中每个字段的多个错误,并循环以确保在子表单级别清除错误

var app = angular.module('plunker', []);
app.controller('MainCtrl', ["$scope", function($scope) 
  $scope.isValidationRequired = true;
    var rootForm = "form";
    function setAllInputsDirty(scope) 
        angular.forEach(scope, function(value, key) 
            // We skip non-form and non-inputs
            if (!value || value.$dirty === undefined) 
                return;
            
            // Recursively applying same method on all forms included in the form except the parent form
            if (value.$addControl && key !== "$$parentForm") 
                return setAllInputsDirty(value);
            
            if (value.$validate)
                value.$validate();
            
            // Setting inputs to $dirty, but re-applying its content in itself
            if (value.$setViewValue) 
                //debugger;
                return value.$setViewValue(value.$viewValue);
            
        );
    

  $scope.$watch(function() 
    $scope.changeValidity();
, true);

    $scope.changeValidity = function(theForm) 
        debugger;
        //This will check if validation is truned off, it will 
        // clear all validation errors
        if (!theForm) 
          theForm = $scope[rootForm];
        
        if ($scope.isValidationRequired === "false") 
            for (var error in theForm.$error) 
                errTypeArr = theForm.$error[error];
                angular.forEach (errTypeArr, function(value, idx) 
                    var theObjName = value.$name;
                    var theObj = value;
                    if (theObj.$addControl) 
                        //This is a subform, so call the function recursively for each of the children
                        var isValid=false;
                        while (!isValid) 
                            $scope.changeValidity(theObj);
                            isValid = theObj.$valid;
                        
                     else 
                      while (theObj.$error[error]) 
                          theObj.$setValidity(error, true);
                      
                    
                )
            
         else 
            setAllInputsDirty($scope);
        
    

]);

【讨论】:

以上是关于使用“ng-form”启用/禁用嵌套子表单的角度表单验证的主要内容,如果未能解决你的问题,请参考以下文章

子查询(嵌套子查询)

在 Access VBA 中将第二个嵌套子表单复选框设置为 true

在嵌套子查询中显示配置单元分区

坚持编写这个嵌套子查询,被加入表的步骤弄糊涂了

sql优化-表容量大嵌套子查询

jOOQ - 加入嵌套子查询