Knockoutjs.com - Grid editor example
http://knockoutjs.com/examples/gridEditor.html
by bmccord
HTML
<script src="https://raw.github.com/SteveSanderson/knockout/master/build/output/knockout-latest.debug.js"></script>
<script src="https://raw.github.com/ericmbarnard/Knockout-Validation/master/Dist/knockout.validation.js"></script>
<div class='liveExample'>
<span data-bind='text: errors().length'></span>
<p>You have asked for <span data-bind='text: gifts().length'> </span> gift(s)</p>
<table data-bind='visible: gifts().length > 0'>
<thead>
<tr>
<th>Gift name</th>
<th>Price</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: gifts'>
<tr>
<td><input data-bind='value: name' /></td>
<td><input data-bind='value: price' /></td>
<td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
</tr>
</tbody>
</table>
<button data-bind='click: addGift'>Add Gift</button>
<button data-bind='enable: gifts().length > 0, click:save' type='submit'>Submit</button>
</div>
CSS
body { font-family: arial; font-size: 14px; }
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }
.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; }
.liveExample td input { width: 13em; }
tr { vertical-align: top; }
.liveExample input.error { border: 1px solid red; background-color: #FDC; }
.liveExample span.error { display: block; color: Red; font-size: 0.8em; }
.liveExample th { font-weight: bold; }
li { list-style-type: disc; margin-left: 20px; }
JavaScript
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.configure({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null,
grouping: {deep:true},
errorClass: "error",
decorateElement: true
});
var GiftModel = function(gifts) {
var self = this;
self.gifts = ko.observableArray(gifts);
self.addGift = function() {
self.gifts.push({
name: ko.observable("").extend({ required: true }),
price: ko.observable("").extend({ required: true })
});
};
self.removeGift = function(gift) {
self.gifts.remove(gift);
};
self.save = function(form) {
if (self.errors().length == 0) {
alert("Could now transmit to server: " + ko.toJSON(self.gifts));
}
else {
self.errors.showAllMessages();
}
// To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
};
self.errors = ko.validation.group(self);
};
var viewModel = new GiftModel([
{ name: ko.observable("Tall Hat").extend({ required: true }), price: ko.observable("39.95").extend({ required: true })},
{ name: ko.observable("Long Cloak").extend({ required: true }), price: ko.observable("120.00").extend({ required: true })}
]);
//viewModel.errors = ko.validation.group(viewModel);
ko.applyBindings(viewModel);