使用knockout验证来验证可观察数组中的特定项

时间:2015-10-01 17:08:22

标签: validation knockout.js knockout-validation

我有一个可观察的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);
}

1 个答案:

答案 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);,但它们的工作方式完全相同。

&#13;
&#13;
<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;
&#13;
&#13;