Custom binding for unobtrusive validation
by bombo
HTML
<script src="https://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.js"></script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-1.2.0.debug.js"></script>
<script src="https://github.com/brandonaaron/livequery/raw/master/jquery.livequery.js"></script>
<script src="https://github.com/jzaefferer/jquery-validation/raw/master/jquery.validate.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js"></script>
<script id="rowTmpl" type="text/html">
<tr>
<td>
<input name="rowInput${Id}" type="text" data-bind="value: input, dataVal: inputVal" />
<span class="field-validation-valid" data-valmsg-for="rowInput${Id}" data-valmsg-replace="true" data-bind="text: error">
No error
</span>
</td>
<td>
<select name="rowSelect${Id}" data-bind="options: ViewModel.list, optionsValue: 'key', optionsText: 'value', optionsCaption: 'Choose...', value: selected, dataVal: selectVal"></select>
<span class="field-validation-valid" data-valmsg-for="rowSelect${Id}" data-valmsg-replace="true">No Error</span>
</td>
</tr>
</script>
<form id="myForm">
<div>
Does not work in IE at the moment. Seems to be linked to the https protocol of some resources.
</div>
<table>
<thead>
<tr>
<td>Input</td>
<td>Select</td>
</tr>
</thead>
<tbody data-bind="template: { name: 'rowTmpl', foreach: rows, afterAdd: reparse }"></tbody>
</table>
<button data-bind="click: addRow">Add row</button>
<button data-bind="click: validate">Validate</button>
</form>
CSS
.field-validation-valid, .field-validation-error {
display: none;
}
.input-validation-error {
border: 1px solid #f00;
background: #fee;
}
JavaScript
(function ($) {
$.validator.unobtrusive.parseDynamicContent = function (selector) {
//use the normal unobstrusive.parse method
$.validator.unobtrusive.parse(selector);
//get the relevant form
var form = $(selector).first().closest('form');
//get the collections of unobstrusive validators, and jquery validators
//and compare the two
var unobtrusiveValidation = form.data('unobtrusiveValidation');
var validator = form.validate();
$.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
if (validator.settings.rules[elname] === undefined) {
var args = {};
$.extend(args, elrules);
args.messages = unobtrusiveValidation.options.messages[elname];
$('[name=' + elname + ']').rules("add", args);
} else {
$.each(elrules, function (rulename, data) {
if (validator.settings.rules[elname][rulename] === undefined) {
var args = {};
args[rulename] = data;
args.messages = unobtrusiveValidation.options.messages[elname][rulename];
$('[name=' + elname + ']').rules("add", args);
}
});
}
});
};
})($);
ko.bindingHandlers.dataVal = {
update: function (element, valueAccessor) {
var values = ko.utils.unwrapObservable(valueAccessor()),
prefix = 'data-val';
if (values === {} || typeof values === "string") {
throw "Please specify name-value pairs for unobtrusive validation binding!";
}
$(element).attr(prefix, true);
for (var prop in values) {
$(element).attr(prefix + '-' + prop, values[prop]);
}
}
};
var viewModel = {
list: ko.observableArray([
{ key: "1", value: "Eins" },
{ key: "2", value: "Zwei" },
{ key: "3", value: "Drei" }
]),
rows: ko.observableArray(),
mainInput: ko.observable(),
};
var Row = function(viewModel, id, inputVal, selectVal) {
...