How can I manage a master/detail UI using nested classes within a view model
https://groups.google.com/d/topic/knockoutjs/hU7DMwikCEc/discussion
by gurkavcu
HTML
<script src="https://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.js"></script>
<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/base/jquery-ui.css">
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th></th>
<th></th>
</tr>
<tbody data-bind="template: { name: 'productsTmpl', foreach: productList }"></tbody>
</table>
<button data-bind="click: addProduct">Add Product</button>
<script id="productsTmpl" type="text/html">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
<td>
<button data-bind="click: function() { viewModel.editProduct($data) }">Edit</button>
</td>
<td>
<button data-bind="click: function() { viewModel.removeProduct($data) }">Delete</button>
</td>
</tr>
</script>
<hr />
<div id="details" data-bind="template: { name: 'editTmpl', data: selectedProduct }, openDialog: selectedProduct">
</div>
<script id="editTmpl" type="text/html">
<p>
<label>ID: </label>
<input data-bind="value: editId" />
</p>
<p>
<label>Name: </label>
<input data-bind="value: editName" />
</p>
</script>
CSS
td { padding: 5px; }
input { width: 100px; margin: 10px; }
label: { width: 100px; }
JavaScript
$(function() {
//set up dialog
$("#details").dialog({
autoOpen: false,
resizable: false,
modal: true,
buttons: {
"Accept": function() {
viewModel.accept();
$(this).dialog("close");
},
Cancel: function() {
viewModel.cancel();
$(this).dialog("close");
}
}
});
});
function Product(id, name, isNew) {
this.id = ko.observable(id);
this.name = ko.observable(name);
this.isNew = isNew;
this.editId = ko.observable(id);
this.editName = ko.observable(name);
//persist edits to real values on accept
this.accept = function() {
this.id(this.editId()).name(this.editName());
}.bind(this);
//reset to originals on cancel
this.cancel = function() {
this.editId(this.id()).editName(this.name());
}.bind(this);
}
var viewModel = {
productList: ko.observableArray([
new Product(1, "one"),
new Product(2, "two"),
new Product(3, "three"),
new Product(4, "four")
]),
selectedProduct: ko.observable(),
editProduct: function(productToEdit) {
viewModel.selectedProduct(productToEdit);
//$("#details").dialog("open"); //let's put this in a custom binding handler called "openDialog"
},
addProduct: function() {
viewModel.selectedProduct(new Product(0, "", true));
},
removeProduct: function(product) {
viewModel.productList.remove(product);
},
accept: function() {
var selected = viewModel.selectedProduct();
selected.accept();
if (selected.isNew) {
viewModel.productList.push(new Product(selected.id(), selected.name()));
}
viewModel.selectedProduct("");
},
cancel: function() {
viewModel.selectedProduct().cancel();
viewModel.selectedProduct("");
}
};
//custom binding handler that...