如何验证使用ng-repeat,ng-show(angular)动态创建的输入

PFr*_*ise 166 html validation grid angularjs

我有一个使用ng-repeat创建的表.我想为表中的每个元素添加验证.问题是每个输入单元格与其上方和下方的单元格具有相同的名称.我试图使用该{{$index}}值来命名输入,但尽管HTML中的字符串文字显示正确,但它现在正在工作.

这是我现在的代码:

<tr ng-repeat="r in model.BSM ">
   <td>
      <input ng-model="r.QTY" class="span1" name="QTY{{$index}}" ng-pattern="/^[\d]*\.?[\d]*$/" required/>
      <span class="alert-error" ng-show="form.QTY{{$index}}.$error.pattern"><strong>Requires a number.</strong></span>
      <span class="alert-error" ng-show="form.QTY{{$index}}.$error.required"><strong>*Required</strong></span>
   </td>
</tr>
Run Code Online (Sandbox Code Playgroud)

我已经尝试删除{{}}from索引,但这也不起作用.截至目前,输入的验证属性工作正常,但不显示错误消息.

有人有什么建议吗?

编辑:除了下面的好答案,这里有一篇博客文章更详细地介绍了这个问题:http://www.thebhwgroup.com/blog/2014/08/angularjs-html-form-design-part-2 /

Hof*_*ffZ 222

自从问到这个问题以来,Angular团队已经通过动态创建输入名称来解决了这个问题.

使用Angular 1.3及更高版本,您现在可以执行以下操作:

<form name="vm.myForm" novalidate>
  <div ng-repeat="p in vm.persons">
    <input type="text" name="person_{{$index}}" ng-model="p" required>
    <span ng-show="vm.myForm['person_' + $index].$invalid">Enter a name</span>
  </div>
</form>
Run Code Online (Sandbox Code Playgroud)

演示

Angular 1.3还引入了ngMessages,这是一种更强大的表单验证工具.您可以使用与ngMessages相同的技术:

<form name="vm.myFormNgMsg" novalidate>
    <div ng-repeat="p in vm.persons">
      <input type="text" name="person_{{$index}}" ng-model="p" required>
      <span ng-messages="vm.myFormNgMsg['person_' + $index].$error">
        <span ng-message="required">Enter a name</span>
      </span>
    </div>
  </form>
Run Code Online (Sandbox Code Playgroud)

  • 辉煌 - 比指令更简单.谢谢. (2认同)
  • 这比完成指令更完美,更容易 - 可以将表单传递给组件并使用此方法.谢了哥们! (2认同)

pko*_*rce 195

AngularJS依赖输入名称来公开验证错误.

不幸的是,截至今天,不可能(不使用自定义指令)动态生成输入名称.实际上,检查输入文档我们可以看到name属性只接受字符串.

要解决"动态名称"问题,您需要创建一个内部表单(请参阅ng-form):

<div ng-repeat="social in formData.socials">
      <ng-form name="urlForm">
            <input type="url" name="socialUrl" ng-model="social.url">
            <span class="alert error" ng-show="urlForm.socialUrl.$error.url">URL error</span>
      </ng-form>
  </div>
Run Code Online (Sandbox Code Playgroud)

另一种选择是为此编写自定义指令.

这是jsFiddle显示ngForm的用法:http://jsfiddle.net/pkozlowski_opensource/XK2ZT/2/

  • @Blowsie你在这里没有嵌套真实的形式,而是`ng-form` DOM元素,所以这里与其他SO问题的链接无关. (11认同)
  • 应该编辑这个答案:问题https://github.com/angular/angular.js/issues/1404自AngularJS 1.3.0(2014年9月提交)以来已经解决 (11认同)
  • 大.应该注意的是,如果`ng-repeat`绑定在`table tr`上,那么你必须使用`ng-form ="myname"`attr. (7认同)
  • 我无法想象嵌套表单是解决方案.谢谢你的回答! (2认同)
  • 那很棒.但是有多个具有相同名称的文本框是否有效? (2认同)

Al *_*hri 13

如果您不想使用ng-form,则可以使用将更改表单名称属性的自定义指令.将此指令作为属性放在与ng-model相同的元素上.

如果您正在使用其他指令,请注意它们没有设置"terminal"属性,否则此函数将无法运行(假设它具有-1的优先级).

例如,当将该指令与ng-options一起使用时,必须运行这一行monkeypatch:https: //github.com/AlJohri/bower-angular/commit/eb17a967b7973eb7fc1124b024aa8b3ca540a155

angular.module('app').directive('fieldNameHack', function() {
    return {
      restrict: 'A',
      priority: -1,
      require: ['ngModel'],
      // the ngModelDirective has a priority of 0.
      // priority is run in reverse order for postLink functions.
      link: function (scope, iElement, iAttrs, ctrls) {

        var name = iElement[0].name;
        name = name.replace(/\{\{\$index\}\}/g, scope.$index);

        var modelCtrl = ctrls[0];
        modelCtrl.$name = name;

      }
    };
});
Run Code Online (Sandbox Code Playgroud)

我经常发现使用ng-init将$ index设置为变量名是很有用的.例如:

<fieldset class='inputs' ng-repeat="question questions" ng-init="qIndex = $index">
Run Code Online (Sandbox Code Playgroud)

这会将您的正则表达式更改为:

name = name.replace(/\{\{qIndex\}\}/g, scope.qIndex);
Run Code Online (Sandbox Code Playgroud)

如果您有多个嵌套的ng-repeats,现在可以使用这些变量名而不是$ parent.$ index.

指令的"终端"和"优先级" 的定义:https://docs.angularjs.org/api/ng/service/ $ compile#directive-definition-object

关于ng-option monkeypatch需求的Github评论:https : //github.com/angular/angular.js/commit/9ee2cdff44e7d496774b340de816344126c457b3#commitcomment-6832095 https://twitter.com/aljohri/status/482963541520314369

更新:

您也可以使用ng-form进行此操作.

angular.module('app').directive('formNameHack', function() {
    return {
      restrict: 'A',
      priority: 0,
      require: ['form'],
      compile: function() {
        return {
          pre: function(scope, iElement, iAttrs, ctrls) {
            var parentForm = $(iElement).parent().controller('form');
            if (parentForm) {
                var formCtrl = ctrls[0];
                delete parentForm[formCtrl.$name];
                formCtrl.$name = formCtrl.$name.replace(/\{\{\$index\}\}/g, scope.$index);
                parentForm[formCtrl.$name] = formCtrl;
            }
          }
        }
      }
    };
});
Run Code Online (Sandbox Code Playgroud)

  • 只是为了说清楚,这个答案没有被选中,并不表示它不是最好的答案.它刚刚问到最初问题后差不多2年就发布了.如果遇到同样的问题,我会考虑这个答案和tomGreen的选择答案. (3认同)

小智 11

在使用ng-repeat指令的标记内部使用ng-form指令.然后,您可以使用ng-form指令创建的作用域来引用通用名称.例如:

    <div class="form-group col-sm-6" data-ng-form="subForm" data-ng-repeat="field in justificationInfo.justifications"">

        <label for="{{field.label}}"><h3>{{field.label}}</h3></label>
        <i class="icon-valid" data-ng-show="subForm.input.$dirty && subForm.input.$valid"></i>
        <i class="icon-invalid" data-ng-show="subForm.input.$dirty && subForm.input.$invalid"></i>
        <textarea placeholder="{{field.placeholder}}" class="form-control" id="{{field.label}}" name="input" type="text" rows="3" data-ng-model="field.value" required>{{field.value}}</textarea>

    </div>
Run Code Online (Sandbox Code Playgroud)

相信:http://www.benlesh.com/2013/03/angular-js-validating-form-elements-in.html