我正在编写一个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记录。您仍然可以像我在上面的图片中那样测试问题。
在下拉之前
更改从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);
}
});
}
};
});
我现在选择实际字段并更改类,使其在正则表达式不匹配时无效。这样,“保存”按钮也会失效。这在下拉列表中更改时有效,但它会以某种方式破坏已编译的元素。
答案 0 :(得分: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
答案 1 :(得分: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>
答案 2 :(得分: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,那么要保留输入的值,请执行以下操作:
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(返回一个承诺---&gt;异步强大的XD)中你重新设置输入的值并瞧!!
答案 3 :(得分:0)
我认为解决方案是观看“record.type”模型并更改它,触发新的正则表达式验证。但是为了做到这一点,模型“record.content”经历了一个你可以通过代码执行的更改。