KnockoutJS & jQuery Datatable custom binding (jQueryUI)
a custom knockout binding
works on vanilla 3.4 knockout
by zachpainter77
HTML
<script src="//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js"></script>
<script src="//code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>
<button data-bind="click: add">ADD</button> Toggle Editing Mode <span data-bind="text: getEditMode"></span>
<input type="checkbox" data-bind="checked: inline" />
<br />
<br/>
<button data-bind="click: removeAll">Remove All</button>
<br />
<br />
<div id="wrapper">
<table id="example" style="width:100%" class="table table-striped table-bordered dataTable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
<th>Remove</th>
<th>Edit</th>
</tr>
</thead>
<tbody data-bind="dataTablesForEach: {data: people, dataTableOptions: {
jQueryUI: true,
scrollY: 250,
paging: true,
dom: 'rtip',
columns:[
{width: '30px'},
{width: '100px'},
{width: '100px'},
{width: '100px'},
{width:'100px'}
]
}
}">
<tr style="height:50px;">
<td><span data-bind="text: id" />
</td>
<td style="width:50px;"> <span data-bind="text: first, visible:!isEdit()"></span>
<input class="form-control input-sm" data-bind="textInput: first, visible: isEdit()" style="width:95%" />
...
CSS
.ui-buttonset .ui-button {
margin-left: 0;
margin-right: 0;
}
body{
background:white;
}
JavaScript
ko.bindingHandlers.dataTablesForEach = {
page: 0,
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor());
ko.unwrap(options.data);
if(options.dataTableOptions.paging){
valueAccessor().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 options = ko.unwrap(valueAccessor()),
key = 'DataTablesForEach_Initialized';
ko.unwrap(options.data);
var table;
if(!options.dataTableOptions.paging){
table = $(element).closest('table').DataTable();
table.destroy();
}
ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);
table = $(element).closest('table').DataTable(options.dataTableOptions);
if (options.dataTableOptions.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) && (options.data || options.length))
ko.utils.domData.set(element, key, true);
...