DataTables & Knockout Integration

by Shrikrishna Gupta

HTML

<link rel="stylesheet" href="https://raw.github.com/DataTables/DataTables/master/media/css/demo_table_jui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.15/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<button data-bind="click: addRecord">Add</button>
<button data-bind="click: removeRecord">Remove</button>
<br /><br />

<span data-bind="text: tableRecordsJson"></span>
<br /><br />
<!-- Note: I'm not too happy about having to pass the column names into this data binding string.  I need to do this so I can initialise DataTables with columns with mDataProps set.  It was my hope that DataTables would be able to figure out the names of the columns purely off the data source, but this doesn't seem to be how DataTables operates. -->
<table id="testTable" data-bind="dataTable: { rowTemplate: 'rowTemplate', dataSource: tableRecords, columns: ['column1', 'column2', 'column3'], options: tableOptions }">
    <thead>
        <tr>
            <td>Column 1</td>
            <td>Column 2</td>
            <td>Column 3</td>
        </tr>
    </thead>
</table>

<!-- This jquery template is used by DataTables to print out each row.  Knockout has special support for templates, so I use some knockout vodoo in the custom knockout data binding to print this template every time the fnRowCallback is fired. -->
<script id="rowTemplate" type="text/html">
    <td>
        
        <input data-bind="value: column1, valueUpdate: 'keypress'" /><br />
        <span data-bind="text: column1"></span>
    </td>
    <td>
        <input data-bind="value: column2, valueUpdate: 'keypress'" /><br />
        <span data-bind="text: column2"></span>
    </td>
    <td>
        <input data-bind="value: column3, valueUpdate: 'keypress'" /><br />
        <span data-bind="text: column3"></span>
    </td>
</script>



<div style="border:1px solid gray; margin-top:10px;">
<p>
Each row in the table...

CSS

tr
{
     border: 1px solid green;   
}

p
{
     margin-bottom: 10px;
     margin-top: 5px;   
}

JavaScript

//********************************************************************************************
// Utility Functions
//
String.prototype.endsWith = function (suffix) {
  return (this.substr(this.length - suffix.length) === suffix);
};

String.prototype.startsWith = function(prefix) {
  return (this.substr(0, prefix.length) === prefix);
};
//
// End Utility Functions
//********************************************************************************************

//********************************************************************************************
// Begin Custom Knockout DataTables Binding
//
ko.bindingHandlers.dataTable =
{
    //
    // Fires when the DataTables binding is initialised.
    //
    init: function (element, valueAccessor, allBindingsAccessor, viewModel)
    {
        var binding = ko.utils.unwrapObservable(valueAccessor());

        var options = {};

        // ** Initialise the DataTables options object with the data-bind settings **
        // Clone the options object found in the data bindings. This object will form the base for the DataTable initialisation object.
        if (binding.options)
            options = ko.toJS(binding.options);

        // Define the tables columns.
        if (binding.columns && binding.columns.length)
        {
            options.aoColumns = [];
            
            ko.utils.arrayForEach(binding.columns, function (col)
            {
                options.aoColumns.push({ mDataProp: col });
            });
        }

        // Register the row template to be used with the DataTable.
        if (binding.rowTemplate && binding.rowTemplate !== '')
        {
            options.fnRowCallback = function (row, data, displayIndex, displayIndexFull)
            {
                ko.renderTemplate(binding.rowTemplate, data, null, row, "replaceChildren");
                return row;
            };
        }

        // Set the data source of the DataTable.
        if (binding.dataSource)
        {
           ...