JSFiddle - React, Tailwind, and code Playground
by zachpainter77
HTML
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdn.datatables.net/1.10.10/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.10/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/fixedcolumns/3.2.0/css/fixedColumns.dataTables.min.css">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Select</th>
<th>Full Name</th>
<th>Position</th>
<th>Office</th>
<th>Start Date</th>
<th>Salary</th>
</tr>
</thead>
<tbody data-bind="dataTablesForEach : {
data: employees,
options: {
deferRender: true,
paging: true,
fixedColumns: {
leftColumns: 2
},
scrollX: true
}
}">
<tr>
<td>
<input data-bind="checked: selectedEmployees, checkedValue: name" type="checkbox" />
</td>
<td data-bind="text: name"></td>
<td data-bind="text: position"></td>
<td data-bind="text: office"></td>
<td data-bind="text: startDate"></td>
<td data-bind="text: salary"></td>
</tr>
</tbody>
</table>
CSS
/* Ensure that the demo table scrolls */
th,
td {
white-space: nowrap;
}
div.dataTables_wrapper {
width: 600px;
margin: 0 auto;
}
JavaScript
ko.bindingHandlers.dataTablesForEach = {
page: 0,
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var binding = ko.utils.unwrapObservable(valueAccessor());
if (binding.options.paging) {
binding.data.subscribe(function(changes) {
var table = $(element).closest('table').DataTable();
ko.bindingHandlers.dataTablesForEach.page = table.page();
table.destroy();
}, null, 'arrayChange');
}
var nodes = Array.prototype.slice.call(element.childNodes, 0);
ko.utils.arrayForEach(nodes, function(node) {
if (node && node.nodeType !== 1) {
node.parentNode.removeChild(node);
}
});
return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var binding = ko.utils.unwrapObservable(valueAccessor()),
key = 'DataTablesForEach_Initialized';
var table;
if (!binding.options.paging) {
table = $(element).closest('table').DataTable();
table.destroy();
}
ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);
table = $(element).closest('table').DataTable(binding.options);
if (binding.options.paging) {
if (table.page.info().pages - ko.bindingHandlers.dataTablesForEach.page === 0) {
table.page(--ko.bindingHandlers.dataTablesForEach.page).draw(false);
} else {
table.page(ko.bindingHandlers.dataTablesForEach.page).draw(false);
}
}
if (!ko.utils.domData.get(element, key) && (binding.data || binding.length)) {
ko.utils.domData.set(element, key, true);
}
return {
controlsDescendantBindings: true
};
}
};
var vm = function() {
this.employees = ko.observableArray([{
"name": "Airi Satou",
"position": "Accountant",
"office": "Tokyo",
"startDate": "28th Nov 08",
"salary": "$162,700 "
}, {
"name": "Angelica Ramos",
"position": "Chief Executive Officer...