9

我正在编写一个 AngularJS 应用程序,在这个应用程序中有一个域管理工具。选择域后,我在表中生成域记录,让用户编辑每一行。由于字段是动态创建的,我使用 ng-form 来单独验证每一行,因为它们共享相同的名称。

每个域记录都有一个内容字段,其中包含 IP、CNAME 等。我使用从基于选择的记录类型(A、CNAME、TXT 等)的函数生成的正则表达式模式验证此字段。

问题是,当我编辑一条 A 记录,然后将记录类型更改为 CNAME 时,表单仍然显示为有效,因为没有对内容字段执行新的验证。我重新验证它的唯一方法是开始在内容字段中输入,然后可以正常工作。

检查以下图片:

我在 A 记录上按编辑,一切看起来都很好: 在此处输入图像描述

我将记录类型更改为 CNAME,即使正则表达式更改,表单仍然显示有效。当我更改类型时,我希望重新验证内容(1.2.3.4),因为它是一个新的正则表达式: 在此处输入图像描述

我开始在内容字段中输入,现在表单正确变为无效。我希望在更改记录类型时发生这种情况,而不仅仅是在我再次开始输入时: 在此处输入图像描述

#Slim version of the template to give you an idea on whats going on
<form novalidate name="recordForm" class="css-form" ng-controller="EditRecordCtrl">

    <table>

        <tr ng-repeat="record in domain.data.0" class="gradeA">

            <td ng-init="startingTypeData = record.type" class="domains-td" ng-switch on="record.edit">
                <span ng-switch-default>{{record.type}}</span>
                <span ng-switch-when="true">
                    <select ng-change="domainRecordContentType(record.type)" ng-init="domainRecordContentType(record.type)" ng-model="record.type" ng-options="c for c in domainRecordTypes" class="span12">
                    </select>
                </span>
            </td>

            <td ng-init="startingContentData = record.content" class="domains-td validation-dropdown-error-parent" ng-switch on="record.edit">
                <span ng-switch-default>{{record.content}}</span>
                <span ng-switch-when="true">
                    <ng-form name="innercContentForm">
                        <span class="validation-dropdown-error" ng-show="innercContentForm.content.$error.pattern">
                            {{ 'RECORD_EDIT_FORM_RECORD_CONTENT_PATTERN_MSG' | translate }} ( {{ record.type }} )
                        </span>
                        <input type="text" ng-model="record.content" name="content" required class="span12 edit-record-input" ng-pattern="domainRecordContentRegex.0" required />
                    </ng-form>
                </span>
            </td>

        </tr>

    </table>

</form>

更改下拉菜单时如何重新验证输入字段?

Plunker 示例:http ://plnkr.co/edit/VAR5ho 注意!第一行没有显示 A 记录的小错误。您仍然可以像我在上图中所做的那样测试问题。

使用 Thomas 自定义指令进行更新

在更改下拉列表之前 在此处输入图像描述

将第一个下拉列表从 A 更改为 CNAME 后,所有内容字段都被擦除 在此处输入图像描述

更新保存按钮

<button ng-disabled="recordForm.$invalid" ng-switch-when="true" ng-if="hideRecordType(record.type)" ng-click="recordForm.$valid && editRecord(record, domainId); record.edit=false; $parent.startingNameData=record.name; $parent.startingTypeData=record.type; $parent.startingContentData=record.content; $parent.startingTTLData=record.ttl; $parent.startingPrioData=record.prio" type="submit" class="btn btn-block btn-primary btn-icon" ><i></i>{{ 'DOMAINS_SAVE_BUTTON' | translate }}</button>

最后更新..关于编译元素的奇怪行为

我按下编辑,它进入我的正常编辑视图 在此处输入图像描述

我开始输入一个新的 IP 地址,直到它变得有效 在此处输入图像描述

如果我在一次有效后使内容无效,例如添加一个点,则该值将被清除。为什么? 在此处输入图像描述

当前基于 Thomas 代码的指令:

domainModule.directive('revalidate', function($compile) {
    return {
        restrict: 'A',
        link : function (scope, element, attrs) {
          scope.$watch(attrs.ngModel, function (v) {
              var reg = scope.$parent.domainRecordContentRegex[0];

              if(!$(element).parent().parent().next().find('ng-form').find('input').val().match(reg)){

                  $compile($(element).parent().parent().next().find('ng-form').children('input[name="content"]').removeClass('ng-valid-pattern'))(scope);
                  $compile($(element).parent().parent().next().find('ng-form').children('input[name="content"]').addClass('ng-invalid-pattern'))(scope);

              }

            });
        }
    };
});

如果正则表达式不匹配,我现在选择实际字段并更改类以使其无效。这样保存按钮也会失效。这在下拉列表中更改时有效,但它会以某种方式破坏已编译的元素。

4

4 回答 4

4

要触发验证,在选择的 ng-change 中将输入的值设置为其值。将您的 plunker 中的第 44 行更改为

<select ng-change="domainRecordContentType(record.type);innercContentForm.content.$setViewValue(innercContentForm.content.$viewValue)" ng-init="domainRecordContentType(record.type)" ng-model="record.type" ng-options="c for c in types">

更新了 plunker http://plnkr.co/edit/D1AFHi

信用:https ://stackoverflow.com/a/17102401/69362

于 2013-09-18T18:23:20.637 回答
3

我认为最好的解决方案是创建自己的验证指令:

.directive('myValidRec', function () {
  var genRegex = function(type){ //...
  };
  return {
    require:'ngModel',
    link: function (scope, el, attrs, ngModel) {

      var validate = function(data){
        var regex = genRegex(scope.$eval(attrs.myValidRec));
        if(regex){
          ngModel.$setValidity('record', regex[0].test(data));  
        }
        return data;
      };

      // triggers validation when the model value changes
      ngModel.$formatters.push(validate);
      ngModel.$parsers.push(validate);

      // triggers validation when the user changes the record type
      scope.$watch(attrs.myValidRec,function(){
        validate(scope.$eval(attrs.ngModel));
      });
    }
  }
});

这允许更清晰的标记:

<td>
  <select ng-model="record.type" ng-options="c for c in types">
  </select>
</td>

<td>
  <ng-form name="innercContentForm">
    <span ng-show="innercContentForm.content.$error.record">
      Pattern error ( {{ record.type }} )
    </span>
    <input type="text" ng-model="record.content" name="content" 
           my-valid-rec="record.type" required />
  </ng-form>
</td>

看看这个 plnkr:http ://plnkr.co/edit/QzQdYN?p=preview

于 2013-09-22T09:04:50.183 回答
1

您可以使用下拉菜单上的指令来做到这一点:

angular.module('App').directive('revalidate', function($compile) {
return {
    restrict: 'A',
    link : function (scope, element, attrs) {
      scope.$watch(attrs.ngModel, function (v) {
          var reg = scope.$parent.domainRecordContentRegex[0];
          if(!$(element).parent().next().find('ng-form').find('input').val().match(reg)){
              $compile($('button[type="submit"]').attr('ng-disabled', "true"))(scope);  
          }

        });
      }
    }
});

在此指令中,您正在查看下拉菜单的模型值或采用该指令的元素。

如果值更改,指令将采用输入的值并检查该值是否与控制器中定义的 regEx 模式匹配。如果不是,则调用 $compile 方法将 ng-disabled 属性重新设置为提交按钮。

有效的又来了。

查看文档以详细了解 $compile:http: //docs.angularjs.org/guide/directive

如果您需要更多帮助,希望对您有所帮助:)我很乐意再次为您提供帮助;)!

快乐编码

更新 :

好的,所以如果您 $compile 您的输入,则输入的值会丢失,因为该值尚未保留在范围内...

因此,如果您使用 $compile 它来保持输入的价值,请这样做:

angular.module('App').directive('revalidate', function($compile, $timeout) {
return {
    restrict: 'A',
    link : function (scope, element, attrs) {
      scope.$watch(attrs.ngModel, function (v) {
          var reg = scope.$parent.domainRecordContentRegex[0];
          if(!$(element).parent().next().find('ng-form').find('input').val().match(reg)){
              var value = $(element).parent().next().find('ng-form').find('input').val();
              $compile($(element).parent().next().find('ng-form').find('input').attr('ng-class', "ng-invalid-pattern"))(scope);
              $timeout(function(){
                $(element).parent().next().find('ng-form').find('input').val(value);
              }, 0);
          }

        });
      }
    }
});

在这里,您将输入的值存储在“value” var 中,然后在 $compile 之后执行 $timeout,延迟为 0。

在这个 $timeout (返回一个承诺 ---> 强大的异步 XD)中,您重新设置输入的值,瞧!

于 2013-09-17T07:24:31.790 回答
0

我认为解决方案是观看“record.type”模型并在更改它时触发您的新正则表达式验证。但为了做到这一点,模型“record.content”已经发生了变化,您可以通过代码执行该变化。

于 2013-09-17T07:23:13.077 回答