JSFiddle - React, Tailwind, and code Playground
by robgallen
HTML
<script src="https://rawgithub.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<em>To show editor pattern on grandchildren</em>
<table>
<thead>
<tr>
<th></th>
<th>Period</th>
<th>Price</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: data.Items">
<tr>
<td data-bind="text: Title" class="hdr" colspan="5"></td>
</tr>
<!-- ko foreach: Data -->
<tr>
<td>
<input data-bind="checked: isSelected" type="checkbox" />
</td>
<td data-bind="text: Period"></td>
<td>
<input data-bind="value: Price" type="text" />
</td>
<td>
<input data-bind="value: Amount" type="text" />
</td>
<td>
<button data-bind="click: update">Update</button>
<button data-bind="click: revert">Cancel</button>
</td>
</tr>
<!-- /ko -->
</tbody>
</table>
<hr />
<em>To show isSelected pattern on grandchildren</em>
<ul data-bind="foreach: selectedItems">
<li>
<span data-bind="text: Period"></span> :
<span data-bind="text: Price"></span> x
<span data-bind="text: Amount"></span>
</li>
</ul>
CSS
table {
border-collapse: collapse;
font-family: sans-serif;
}
th, td {
border: 1px solid #ddd;
}
input {
border: 1px solid #bbb;
padding: 2px 5px;
text-align: right;
width: 70px;
}
.hdr {
font-weight: bold;
padding: 5px 10px;
}
JavaScript
// dummy data from api call
var data = {
Items: [{
Title: "This is item one",
Data: [
{ Id: 1, Period: "Dec 2013", Price: "10", Amount: 5 },
{ Id: 2, Period: "Jan 2014", Price: "12", Amount: 6 },
{ Id: 3, Period: "Feb 2014", Price: "15", Amount: 10 }
]
}, {
Title: "This is item two",
Data: [
{ Id: 1, Period: "Dec 2013", Price: "16", Amount: 50 },
{ Id: 2, Period: "Jan 2014", Price: "19", Amount: 45 },
{ Id: 3, Period: "Feb 2014", Price: "21", Amount: 70 }
]
}]
};
var mapping = {
create: function (options) {
var dataMap = {
"Data": {
create: function (opts) {
var item = ko.mapping.fromJS(opts.data);
item.isSelected = ko.observable(false);
// add editor pattern
item.cache = function () {};
item.update = function (data) {
item.cache.latestData = ko.toJS(data);
ko.mapping.fromJS(item.cache.latestData, this);
};
item.revert = function () {
item.update(item.cache.latestData);
};
item.update(opts.data);
return item;
}
}
};
var model = ko.mapping.fromJS(options.data, dataMap);
return model;
}
};
var viewModel = function () {
var self = this;
self.data = ko.mapping.fromJS(data, mapping);
self.selectedItems = ko.computed(function () {
// data.Items[n].Data[n].isSelected
var list = [];
ko.utils.arrayForEach(self.data.Items(), function (item) {
ko.utils.arrayForEach(item.Data(), function (data) {
if (data.isSelected()) {
list.push(data);
}
});
});
...