【问题标题】:AngularJS: Dynamic inputs with form validationAngularJS:带有表单验证的动态输入
【发布时间】:2015-10-22 00:33:15
【问题描述】:

我正在动态地在表单中创建输入。我为此目的创建了这个指令:

// Generate inputs on the fly using BE data.
.directive('inputGenerator', ['$compile', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            id: '@',
            type: '@',
            name: '@',
            attributes: '=',
            ngModel: '=',
            ngDisabled: '='
        },
        link: function (scope, iElement, iAttrs) {
            // Get attributes
            var id         = iAttrs.id,
                type       = iAttrs.type,
                name       = iAttrs.name;

            scope.ngModel[name] = {};

            var extended_attributes = {
              "type": type,
              "id": id,
              "data-ng-model": 'ngModel.' + name + '[\'value\']',
              "name": name,
              "data-ng-disabled": "ngDisabled"
            };

            if ( ! scope.attributes) {
                scope.attributes = {};
            }

            // Append extra attributes to the object
            angular.extend(scope.attributes, extended_attributes);

            // Generate input
            var input = '<input ';

            angular.forEach(scope.attributes, function (value, key) {
                input += key + '="' + value + '" ';
            });

            input += '/>';

            // Compile input element using current scope (directive) variables
            var compiledElement = $compile(input)(scope);

            // Set the file selected name as the model value
            compiledElement.on('change', function () {
                if (this.files && this.files[0].name) {
                    var that = this;
                    scope.$apply(function () {
                        scope.ngModel[name] = {};
                        scope.ngModel[name]['value'] = that.files[0].name;
                    });
                }
            });

            // Replace directive element with generated input
            iElement.replaceWith(compiledElement);
        }
    };
}]);

此 html 行将触发指令:

<input-generator data-name="{{ item.name }}" data-ng-model="inputs.sources" data-attributes="item.attrs" data-type="{{ item.type }}" data-id="inputFile_{{ $index }}" data-ng-disabled="inputs.sources[item.name].selected" />

我在 Angular 1.4.3 上运行。

问题

模型和几乎所有指令在指令中都可以正常工作,但由于某种原因,当添加的输入无效时,表单仍然有效,正如您在这张图片中看到的那样。

我已经试过了:

表单验证的任何 Angular 功能都有效

我调试了 Angular,似乎是附加到表单的输入与指令内编译的输入不同。

我已经在每个输入创建后调用了formName.$setPristine(),但它不起作用。

我无法通过指令访问表单,但我认为这也不是一个好主意。

我已经用 ng-form 标签包装了输入,但没有任何用处。

我尝试使用指令编译方法,但这只是在应用加载时触发一次,并且我有一个选择输入,可以在更改时加载不同的输入。

非常感谢您对此的任何帮助! :)

感谢大家的贡献!!

【问题讨论】:

    标签: javascript angularjs forms validation directive


    【解决方案1】:

    您需要设置动态控件的名称并使用此动态名称进行表单验证。在以下例如您会看到控件的动态名称和 ID,并用于验证 Angular(使用 ng-massages) 更多详情见http://www.advancesharp.com/blog/1208/dynamic-angular-forms-validation-in-ngrepeat-with-ngmessage-and-live-demo

    字段编号为必填项。

    【讨论】:

      【解决方案2】:

      我在使用 Angular v1.5.9 时也遇到了这个问题。这里的主要问题是您正在编译 HTML 模板之前它在 DOM 中,所以 Angular 不知道它是表单的一部分。如果您先添加 HTML,然后进行编译,Angular 会将您的输入视为表单子项,并将用于表单验证。

      查看Form Validation and fields added with $compile的类似答案

      不要这样做:

              var myCompiledString = $compile(myHtmlString)(scope);
              // ...
              element.replaceWith(myCompiledString);
      

      改为这样做:

              var myElement = angular.element(myHtmlString)
              element.replaceWith(myElement) // put in DOM
              $compile(myElement)(scope) // $compile after myElement in DOM
      

      注意:我将更传统的 element 替换为 OP 的 iElement,这是指令 HTML 元素的 jQLite 引用

      【讨论】:

        【解决方案3】:

        你一定要看看我的Angular-Validation Directive/Service。它具有大量功能,我还支持动态输入验证,您还可以传递一个独立的范围,如果您不仅希望拥有动态输入,还希望拥有动态表单,也可以在模态窗口中使用。

        例如,让我们把这个例子看成一个动态表单和在控制器中定义的输入:

        $scope.items.item1.fields = [
           {
              name: 'firstName',
              label:'Enter First Name',
              validation:"required"
            },
            {
              name: 'lastName',
              label: 'Enter Last Name',
              validation:"required"
            }
          ];
          $scope.items.item2 = {
            heading:"Item2",
            formName:"Form2"
          };
          $scope.items.item2.fields = [
           {
              name: 'email',
              label:'Enter Email Id',
              validation:"required"
            },
            {
              name: 'phoneNo',
              label: 'Enter Phone Number',
              validation:"required"
            }
        ];
        

        它将验证绑定到元素,如果您想直接从控制器轻松检查表单有效性,只需使用此

        var myValidation = new validationService({ isolatedScope: $scope });
        
        function saveData() {
            if(myValidation.checkFormValidity($scope.Form1)) {
                alert('all good');
            }
        }
        

        你也可以像这样使用插值

        <input class="form-control" type="text" name="if1"
                ng-model="vm.model.if1"
                validation="{{vm.isRequired}}" />
        

        或者使用单选/复选框来启用/禁用在启用时仍要验证的字段:

        ON <input type="radio" ng-model="vm.disableInput4" value="on" ng-init="vm.disableInput4 = 'on'">
        OFF <input type="radio" ng-model="vm.disableInput4" value="off">
        
        <input type="text" name="input4" 
                ng-model="vm.input4" 
                validation="alpha_dash|min_len:2|required" 
                ng-disabled="vm.disableInput4 == 'on'" />
        

        它确实有很多功能,并且在BowerNuGet 上都可用(在angular-validation-ghiscoding 的标签名称下)。因此,请查看我的库 Angular-ValidationPLUNKER 上的现场演示。

        它具有许多功能(自定义 Regex 验证器、AJAX 远程验证、验证摘要、替代文本错误、使用服务进行动态验证等...)。所以一定要检查Wiki Documentation...最后,它已经用 Protractor 进行了全面测试(超过 1500 个断言),所以不要害怕在生产中使用。

        请注意我是这个库的作者

        【讨论】:

        • 您的解决方案的问题在于您没有编译输入并且它不是完全动态的输入。我的指令创建所有类型的输入,普通输入,textarea,选择等。我意识到当我的指令编译时,会创建一个新的范围,并且在 angular 触发表单验证后应用指令,所以编译时的字段验证是无效,但该表单之前已设置为有效。
        • 问题是这样,如果我从指令访问表单以重置表单验证并重新编译它,我的指令也将被重新编译并产生相同的错误......啊啊啊! !!!
        【解决方案4】:

        但它对我有用。您可以将表单引用传递给指令并直接使用它。

        在下面的代码中,scope.form 用于了解表单的一般状态,scope.name 用于访问输入字段的状态。

        希望对你有帮助

        【讨论】:

          【解决方案5】:

          您需要使用 ng-form 指令作为输入的包装器。

          你可以看到这个here的例子

          【讨论】:

          • 指令“ng-form”的名称可能会导致错误。它不是表格替代品,您只能在真实表格中使用它来动态检查子组,并且单个输入是完全有效的子组。
          • 对不起,我没有读到这个:“我已经用 ng-form 标签包装了输入,但没有任何用处”
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-11-23
          • 1970-01-01
          • 1970-01-01
          • 2013-06-27
          • 1970-01-01
          • 1970-01-01
          • 2014-02-22
          相关资源
          最近更新 更多