Knockout
validation for 2nd level of array
We
have been working with knockout and its validation for some time now. For
validation we simply use .extends() method. Just like : self.ItemName.extend({
required: { message: 'Item Name is required!'} });
But,
when one class has array of another class in it validation for child class
properties becomes troublesome.
Like,
var
PaymentItem = function () {
var
self = this;
self.ItemId
= ko.observable(0);
self.ItemName
= ko.observable('');
self.ItemDescription
= ko.observable('');
self.EMIs
= ko.observableArray([]);
self.IsArchived
= ko.observable(false);
self.Index
= ko.observable(0);
self.errors
= ko.validation.group(self);
};
var
ItemEMI = function () {
var
self = this;
self.EMIId
= ko.observable(0);
self.Amount
= ko.observable();
self.IsArchived
= ko.observable(false);
self.Amount.IsInvalid
= ko.observable(false);
};
Here,
we have one class PaymentItem which has one observable array (self.EMIs) of
another class which is ItemEMI. Here is how it will look:
Now
if we want to write validation for ItemName or description we can simply write
like : self.ItemName.extend({ required: { message: 'Item Name is required!'}
});.
But,
when we do the same for ItemEMIs it will always display first executed error's
error message. Like here if you have placed 2 validation one for required field
and then another for valid amount, then if you click on Save button without
enter amount then it will display like Amount is required. And if you enter
alphanumeric value in Amount field then also it will display same error message
where actually it should display amount is not valid.
Here
if you have another field for ItemEMI class like EMI due date and error occur
for it then also error message will remain the same.
In
the same case if you click on save button without entering amount then it will
display like Amount is required. Now, if you enter valid Amount value then the
error will hide out. Now, if you again enter invalid character value then it
will show error message like "Amount is not valid".
So,
point is it will display error message for first executed error only.
To
overcome this we did the validation in a way that whenever an error happens for
observable array we show the common message. But we will highlight the control
for which error has occurred.
Here
is validation code for this:
self.EMIs.extend(
{
customValidation:
{
message:
eMIErrorMessage, //"EMI due date required!",
params:
{
validator:
function (list) {
var
isValid = true;
for
(var i = 0, len = list.length; i < len; i++) {
var
item = list[i];
if
(item.IsArchived()) continue;
item.Amount.IsInvalid(false);
var
regEx = /^\d{1,9}(\.\d{1,2})?$/;
if
(item.Amount() <= 0 || (!regEx.test(item.Amount()))) {
item.Amount.IsInvalid(true);
isValid
= false;
break;
}
}
console.log(isValid);
return
isValid;
}
}
}
});
Here
we have taken one more observable in ItemEmi class with name
self.Amount.IsInvalid() with default value false. And whenever error occurs in
Amount field we set self.Amount.IsInvalid() to true.
And
in html part we have set code to apply error class when self.Amount.IsInvalid()
has true value.
e.g.
<input type="text" data-bind="value: Amount,
css:{'disable-alt-row': Amount.IsInvalid}" />
So,
if we want to validate duedate then we can take another observable like self.DueDate.IsInvalid() with default value
false and when ever error occurs for it we can it to true and set html part
accordingly.
So,
this way we can handle validation for having class having observable array of
another class in it.
If
you need to check demo of this here is the link: http://jsfiddle.net/bWJTY/19/