我有一个可观察的formField数组,它被渲染到我的表单上的输入/选择字段列表。
每个字段都是一个单独的viewModel,并根据自己的fieldType属性进行渲染(例如 - firstName,lastName,creditCardNumber等...)。
在数据库中,我保留了formTypes定义。对于每个formType,都有一个映射表示为此表单类型显示的所有字段(例如 - formType = Address将具有formFields列表 - Street,City,Country,ZipCode等。)。
这样,我可以根据表单定义及其对应的formFields动态创建不同的表单。
现在,我的问题是我想使用knockout验证来验证formFields的observableArray本身(除了每个特定的formField单独验证工作正常)。我的意思是对具有场间依赖性的整个表单进行验证。例如:
字段:分行号,帐号,帐户持有人姓名,银行名称 验证:(分行号码+帐号)* 13%6 == 3(仅举例)。
字段BranchNumber和AccountNumber是formFields observableArray中的字段viewModel,每当observableArray中的一个项发生更改时,我都需要为表单运行验证。
我的问题是,当数组内的字段值发生变化时,字段间验证不会重新评估errors()属性。
有人可以帮忙吗?
我自己的示例代码比我描述的更复杂,这就是我没有在这里发布的原因。我希望这很清楚。谢谢!
简短示例(仅在表单初始化时调用validate,每次更改observableArray中内部项的值时如何使其运行):
function FormField(formField, parentForm) {
var self = this;
self.detail = ko.observable().extend({
validation: {
validator: function(val) {
isValid = false;
if (typeof self.requiredFieldType === "undefined") {
isValid = true;
} else if ([3, 5, 22].indexOf(self.requiredFieldType) > -1) { // Email, Product Account Email, Giftcard Delivery Email
isValid = val !== "" && emailPattern.test($.trim(val));
} else {
isValid = $.trim(val) !== "";
}
return isValid;
},
message: function() {
if (self.requiredFieldType === 2) {
return 'Please enter a valid Zip Code.';
} else if (self.requiredFieldType === 3 || self.requiredFieldType === 22) {
return 'Invalid Email.';
} else if (self.requiredFieldType === 5) {
return 'Invalid Account Email.';
} else if (self.requiredFieldType === 6) {
return 'Please select your iTunes store.';
} else if (self.requiredFieldType === 7) {
return 'Please enter a phone number.';
} else if (self.requiredFieldType === 9) {
return 'Please enter frequent flyer number.';
} else if (self.requiredFieldType === 10) {
return 'Please enter street.';
} else if (self.requiredFieldType === 11) {
return 'Please enter house #.';
} else if (self.requiredFieldType === 12) {
return 'Please enter city.';
} else if (self.requiredFieldType === 13 || self.requiredFieldType === 23) {
return 'Please enter country.';
} else if (self.requiredFieldType === 15) {
return 'Please enter bank account number.';
} else if (self.requiredFieldType === 16) {
return 'Please enter bank account holder name.';
} else if (self.requiredFieldType === 17) {
return 'Please enter bank name.';
} else if (self.requiredFieldType === 18) {
return 'Please enter bank branch number.';
} else if (self.requiredFieldType === 19) {
return 'Please enter first name.';
} else if (self.requiredFieldType === 20) {
return 'Please enter last name.';
} else if (self.requiredFieldType === 21) {
return 'Please select a currency.';
}
}
}
}).extend({
required: {
message: 'This field is required.'
}
});
self.requiredFieldType = formField.RequiredFieldType;
self.errors = ko.validation.group(self);
}
}
function Form(form) {
var self = this;
self.formName = form.ProductName;
self.formFields = ko.observableArray($.map(form.FormFields, function(jsonFormField) {
return new FormField(jsonFormField, self)
})).extend({
validation: {
validator: function(val) {
return false; // this is being called only once
},
message: function() {}
}
});
self.errors = ko.validation.group(self);
}
答案 0 :(得分:0)
observableArray的验证器只有在有可订阅事件时才会被调用,它不包括修改所包含数组的元素。您可以告诉数组已使用
更新它self.formFields.valueHasMutated();
您需要将订阅附加到每个元素,并订阅订阅valueHasMutated
,可能类似于:
function validateParent () {
self.formFields.valueHasMutated();
}
ko.utils.arrayForEach(self.formFields(), function (item) {
item.detail.subscribe(validateParent);
});
更新:进一步调查,我发现了this link,其中提到了ko.validation.validateObservable()
,这似乎比valueHasMutated
更加重要。< / p>
它们都不会导致重新评估所有字段。这是一个包含标签的片段,以及最后一次验证的标签&#34;字段,说明什么时候改变。请注意,各个字段&#39;标签每次更改时都会更新,但不会在其他标签更新时更新,即使每次更改都会更新上次验证的时间。
我已valueHasMutated
评论validateObservable
赞成vm = {
lastValidated: ko.observable(0)
};
vm.v = ko.observableArray([]).extend({
validation: {
validator: function (val) {
vm.lastValidated((new Date()).getMilliseconds());
}
}
});
function addMember(name) {
var item = ko.observable(name);
item.subscribe(function (newValue) {
ko.validation.validateObservable(vm.v);
//vm.v.valueHasMutated();
});
vm.v.push({
data: item
});
}
addMember('one');
addMember('two');
ko.applyBindings(vm);
,但它们的工作方式完全相同。
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<div data-bind="foreach:v">
<input data-bind="value:data, valueUpdate:'input'" />
</div>
<div data-bind="foreach:v">
<div data-bind="text:data()+((new Date()).getMilliseconds())"></div>
</div>
<div data-bind="text: lastValidated"></div>
&#13;
<?php
$statfile=$_GET['scd'];
if ($statfile=='')
{
$statfile="/et3mach/status.txt";
}
$temps = array();
$brdhover = array();
if (($handle = fopen($statfile, "r")) !== FALSE)
{
while (($data = fgetcsv($handle, 1000, ";")) !== FALSE)
{
if(substr(trim($data[0]), 0, 3) == 'BRD')
{
$board = trim($data[0]); // get the index (e.g "BRD 0") & strip leading or trailing blanks
$temp = trim($data[10]); // the tempreture data is the 10th field; trim that also, to be safe.
$temps[ $board ] = $temp;
$brdhover[ $board ] = $data[11]; // Field 11 is the "hover" text; don't trim that for now...
}
}
fclose($handle);
}
?>
&#13;