knockout validation spike
by manchagnu
HTML
<script src="http://github.com/downloads/SteveSanderson/knockout/jquery.tmpl.js"></script>
<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<script id="errorTemplate" type="text/html">
${$data}}
</script>
<form data-bind="submit: onSubmit">
<label>First Name</label>
<input data-bind="value: firstName, valueUpdate: 'afterkeydown'" type="text">
<span data-bind="template: { name: 'errorTemplate', data: validation.getError(firstName) }"></span>
<br/>
<label>Last Name</label>
<input data-bind="value: lastName, valueUpdate: 'afterkeydown'" type="text">
<span data-bind="template: { name: 'errorTemplate', data: validation.getError(lastName) }"></span>
<br/>
<label>Gender</label>
<select data-bind="value: gender">
<option value=""></option>
<option value="m">Male</option>
<option value="f">Female</option>
</select>
<span data-bind="template: { name: 'errorTemplate', data: validation.getError(gender) }"></span>
<br/>
<input type="submit">
</form>
JavaScript
ko.validation = function() {
var fields_ = [];
function requiredValidator(value) {
return value != null && value !== "";
}
function addFieldValidation(field, validator, message) {
if (!ko.isObservable(field)) {
throw "passed field is not an observable";
}
var validationItem = {
field: field,
validator: validator,
message: message,
error: ko.observable(null)
};
field.subscribe(function(newValue) {
validateField(validationItem, newValue);
});
fields_.push(validationItem);
}
function validateField(validationItem, value) {
if (validationItem.validator(value)) {
validationItem.error(null);
return true;
}
else {
validationItem.error(validationItem.message);
return false;
}
}
var result = {
required: function(field, message) {
addFieldValidation(field, requiredValidator, message);
},
custom: function(field, validator, message) {
addFieldValidation(field, validator, message);
},
validate: function() {
var isValid = true;
for (var i = 0; i < fields_.length; i++) {
var validationItem = fields_[i];
var validationResult = validateField(validationItem, validationItem.field());
if (!validationResult) {
isValid = false;
}
}
return isValid;
},
hasError: function(field) {
return this.getError(field)() != null;
},
getError: function(field) {
for (var i = 0; i < fields_.length; i++) {
var validationItem = fields_[i];
if (field === validationItem.field) {
return validationItem.error;
}
}
...