Validation 使用敲除验证来验证可观察数组中的特定项

Validation 使用敲除验证来验证可观察数组中的特定项,validation,knockout.js,knockout-validation,Validation,Knockout.js,Knockout Validation,我有一个可观察的formFields数组,它被呈现到表单上的输入/选择字段列表中 每个字段都是一个单独的viewModel,并根据其自己的fieldType属性(例如-firstName、lastName、creditCardNumber等)进行渲染 在数据库中,我保留formTypes定义。对于每个表单类型,都有为此表单类型显示的所有字段的映射(例如-formType=Address将有此表单字段列表-街道、城市、国家、ZipCode等) 这样,我可以根据表单定义及其相应的表单字段动态创建不同

我有一个可观察的formFields数组,它被呈现到表单上的输入/选择字段列表中

每个字段都是一个单独的viewModel,并根据其自己的fieldType属性(例如-firstName、lastName、creditCardNumber等)进行渲染

在数据库中,我保留formTypes定义。对于每个表单类型,都有为此表单类型显示的所有字段的映射(例如-formType=Address将有此表单字段列表-街道、城市、国家、ZipCode等)

这样,我可以根据表单定义及其相应的表单字段动态创建不同的表单

现在,我的问题是,我想使用敲除验证来验证formFields的observableArray本身(除了每个特定的formField单独的验证,该验证工作正常)。我的意思是对具有字段间依赖关系的整个表单进行验证。例如:

银行帐户表格: 字段:分行号、账号、账户持有人姓名、银行名称 验证:(分行号+账号)*13%6==3(仅举一个例子)

BranchNumber和AccountNumber字段是formFields observableArray中的field viewModels,每次observableArray中的项目发生更改时,我都需要对表单运行验证

我的问题是,当数组中的字段值更改时,字段间验证不会重新计算errors()属性

有人能帮忙吗

我自己的示例代码比我描述的要复杂得多,这就是为什么我没有在这里发布它。我希望这已经足够清楚了。谢谢


简短示例(仅在表单初始化时调用validate,如何使其在每次ObservalArray内部项的值更改时运行)

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);
}

ObservalArray的验证器仅在其上存在可订阅事件时调用,该事件不包括修改所包含数组的元素。您可以告诉阵列已使用更新

self.formFields.valueHasMutated();
您需要将订阅附加到每个元素,并使订阅调用
valuehassmutated
,可能类似于:

function validateParent () {
  self.formFields.valueHasMutated();
}
ko.utils.arrayForEach(self.formFields(), function (item) {
  item.detail.subscribe(validateParent);
});
更新:进一步调查后,我发现,其中提到了
ko.validation.validateObservable()
,这似乎是一个比
值发生变异更切题的选择

它们都不会导致重新计算所有字段。下面是一个包含标签和“last validated”字段的代码段,以说明在发生更改时会发生什么变化。请注意,各个字段的标签在每次更改时都会更新,但在另一个字段更改时不会更新,即使上次验证的时间随每次更改而更新

我已经注释掉了
valuehassmutated
,取而代之的是
validateObservable
,但它们的工作原理完全相同

vm={
lastValidated:ko.可观察(0)
};
vm.v=ko.observearray([]).extend({
验证:{
验证器:函数(val){
vm.lastValidated((new Date()).getmillizes());
}
}
});
函数addMember(名称){
var项目=可观察的ko(名称);
item.subscribe(函数(newValue){
ko.validation.validateObservable(vm.v);
//vm.v.valueHasMutated();
});
推送({
数据:项目
});
}
添加成员(“一”);
addMember('two');
ko.应用绑定(vm)


恐怕我们必须查看您的数据结构才能了解其工作原理。你能把一个例子(比如你的银行账户表)浓缩到问题的最小程度吗?有时候,在做这些简单的例子时,解决方案会跳出来。@RoyJ现在好点了吗?谢谢。这会不会导致每次更改字段值时都刷新所有字段的视图?有没有一种方法可以在不刷新整个视图的情况下设置这种验证?也许是基于订阅,或者以某种方式手动强制运行验证逻辑?@UriAbramson Fair question,让我思考了一下。但不是,valueHasMutated只会导致变异的可观察对象的订户更新。请参阅更新的答案。