I have an observable array of formFields which is rendered to a list of input / select fields on my form.
Each field is a separate viewModel and rendered according to its own fieldType property (for example - firstName, lastName, creditCardNumber etc...).
In the database, I keep formTypes definition. For each formType, there is a mapping of all the fields that are displayed for this form type (for example - formType=Address will have this list of formFields - Street, City, Country, ZipCode etc..).
This way, I can create different forms dynamically depending on the form definition and its corresponding formFields.
Now, my problem is that I want to use knockout validation to validate the observableArray itself of the formFields (in addition to each specific formField separate validation which works fine). I mean a validation for the entire form with inter-field dependencies. For example:
Bank Account Form:
Fields: Branch Number, Account Number, Account Holder Name, Bank Name Validation: (Branch Number + Account Number) * 13 % 6 == 3 (just an example).
The fields BranchNumber and AccountNumber are field viewModels inside the formFields observableArray and I need the validation to run for the form each time an item inside the observableArray changes.
My problem is that when the field values inside the array change, the inter-field validation is not re-evaluating the errors() property.
Can anybody help?
My own sample code is way more complex than what I described, this is why I didn't post it here. I hope that was clear enough as is. Thanks!
Short example (the validate is only called on form initialization, how do I make it run each time the values of inner items inside the observableArray are changed):
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);
}