JSFiddle - React, Tailwind, and code Playground
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<table>
<thead>
<tr>
<th>Sender</th>
<th>Status Code</th>
<th>Status Msg</th>
<th>Data</th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr>
<td data-bind="text: sender"></td>
<td data-bind="text: statuscode"></td>
<td data-bind="text: statusmsg"></td>
<td data-bind="foreach: data">
<span data-bind="text: name"></span>:
<span data-bind="text: value"></span><br />
</td>
</tr>
</tbody>
</table>
<button type="button" data-bind="click: updateRow">Get More Data</button>
JavaScript
var jsonList1 = '[{"statusmsg":"OK","data":{"status":"stopped"},"sender":"hostname","statuscode":0}]';
var jsonList2 = '[{"statusmsg":"OK","data":{"value":"test","fact":"some_fact"},"sender":"hostname","statuscode":0}]';
function objectToNameValueArray(obj, includeEmpty) {
// Convert associative array into array of name-value pairs
var list = [];
for (var key in obj) {
if (obj[key] || includeEmpty) {
list.push({
name: key,
value: obj[key]
});
}
}
return list;
}
var mappingData = {
key: function(data) {
// Define primary key of item in data array
return ko.utils.unwrapObservable(data.name);
},
};
var mappingRow = {
key: function(data) {
// Define primary key of item in rows array
return ko.utils.unwrapObservable(data.sender);
},
'data': {
create: function(options) {
// Convert to associative array instead of default behaviour
return ko.mapping.fromJS(objectToNameValueArray(options.data), mappingData);
},
update: function(options) {
// Merge with previous data instead of default behaviour
var list = objectToNameValueArray(options.data);
if (options.parent.data) {
ko.utils.arrayForEach(list, function(item) {
var mappedItem = ko.mapping.fromJS(item, mappingData);
var i = options.parent.data.mappedIndexOf(item);
if (i >= 0) {
options.parent.data.replace(ko.utils.unwrapObservable(options.parent.data)[i], mappedItem);
} else {
options.parent.data.push(mappedItem);
}
});
return options.parent.data;
} else {
return ko.mapping.fromJS(list, mappingData);
}
}
}
};
function PageViewModel() {
...