Knockoutjs.com - Contacts Editor
http://knockoutjs.com/examples/contactsEditor.html
by photo_tom
HTML
<script src="http://knockoutjs.com/js/jquery.tmpl.js"></script>
<script src="http://knockoutjs.com/js/knockout-1.2.1.js"></script>
<div class='liveExample'>
<h2>Contacts</h2>
<table class='contactsEditor'>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Phone numbers</th>
</tr>
<tr data-bind='template: "contactsListTemplate" foreach: contacts'> </tr>
</table>
<script id='contactsListTemplate' type='text/html'>
<td>
<input data-bind='value: firstName' />
<div><a href='#' data-bind='click: function() { viewModel.removeContact(contact) }'>Delete</a></div>
</td>
<td><input data-bind='value: lastName' /></td>
<td>
<table>
{{each(i, phone) phones}}
<tr>
<td><input data-bind='value: type' /></td>
<td><input data-bind='value: number' /></td>
<td><a href='#' data-bind='click: function() { viewModel.removePhone(contact, phone) }'>Delete</a></td>
</tr>
{{/each}}
</table>
<a href='#' data-bind='click: function() { viewModel.addPhone(contact) }'>Add number</a>
</td>
</script>
<p>
<button data-bind='click: addContact'>Add a contact</button>
<button data-bind='click: save, enable: contacts().length > 0'>Save to JSON</button>
</p>
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>
</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 TR { vertical-align: top; }
.liveExample TABLE, .liveExample TD, .liveExample TH { padding: 0.2em; border-width: 0; margin: 0; }
.liveExample TD A { font-size: 0.8em; text-decoration: none; }
.liveExample table.contactsEditor > tbody > TR { border-bottom: 1px solid silver; }
.liveExample td input { width: 8em; }
li { list-style-type: disc; margin-left: 20px; }
JavaScript
var viewModel = {
contacts: new ko.observableArray([
{
firstName: "Danny",
lastName: "LaRusso",
phones: [
{
type: "Mobile",
number: "(555) 121-2121"},
{
type: "Home",
number: "(555) 123-4567"}]},
{
firstName: "Sensei",
lastName: "Miyagi",
phones: [
{
type: "Mobile",
number: "(555) 444-2222"},
{
type: "Home",
number: "(555) 999-1212"}]}
]),
addContact: function() {
viewModel.contacts.push({
firstName: "",
lastName: "",
phones: []
});
},
removeContact: function(contact) {
viewModel.contacts.remove(contact);
},
addPhone: function(contact) {
contact.phones.push({
type: "",
number: ""
});
viewModel.contacts.valueHasMutated();
},
removePhone: function(contact, phone) {
ko.utils.arrayRemoveItem(contact.phones, phone);
viewModel.contacts.valueHasMutated();
},
save: function() {
viewModel.lastSavedJson(JSON.stringify(viewModel.contacts(), null, 2));
},
lastSavedJson: new ko.observable("")
};
ko.applyBindings(viewModel);