JSFiddle - React, Tailwind, and code Playground

Knockout Bootstrap server-side tables

by Sybeus

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<div data-bind="template { name: 'table-template', data: tblSelected }"></div>
<script type="text/html" id="selected-th-template">
    <tr>
        <th>Item</th>
        <th></th>
    </tr>
</script>
<script type="text/html" id="selected-td-template">
    <tr>
        <td data-bind="text: name"></td>
        <td>
            <button type="button" class="btn btn-default btn-xs pull-right" data-bind="click: $parent.removeEntry">
                <span class="glyphicon glyphicon-minus"></span>
                Remove
            </button>
        </td>
    </tr>
</script>

<p>
    <div class="input-group">
        <input type="textbox" class="form-control" placeholder="Name" data-bind="value: name"/>
        <span class="input-group-btn">
            <button type="button" class="btn btn-primary" data-bind="click: tblSelected.addEntry"><span class="glyphicon glyphicon-plus"></span> Add</button>
        </span>
    </div>
</p>

<script type="text/html" id="table-template">
    <div class="koTables_wrapper panel panel-default">
        <div class="panel-heading">
            <div class="row">
                <div class="col-sm-4 col-xs-12">
                    <div class="koTables_length">
                        Show
                        <select class="form-control input-sm" data-bind="value: pageSize, options: pageSizes, optionsText: 't', optionsValue: 'v'"></select>
                        entries
                    </div>
                </div>
                <div class="col-sm-4 col-xs-12">
                    <div class="koTables_processing" data-bind="text: status">Initializing...</div>
                </div>
                <div class="col-sm-4 col-xs-12">
                    <div...

CSS

div.koTables_wrapper > .panel-heading {
  padding: 6px;
}

div.koTables_wrapper > .panel-footer {
  padding: 6px;
}

div.koTables_length select {
    display: inline-block;
    vertical-align: middle;
    width: auto;
}

div.koTables_filter input {
    display: inline-block;
    vertical-align: middle;
    width: auto;
}

div.koTables_info {
	/*padding-top: 6px;*/
}

div.koTables_paginate {
	margin: 0px;
    padding: 0px;
}

div.koTables_paginate ul.pagination {
	margin: 0px;
    padding: 0px;
}

td.koTables_empty {
    text-align: center;
}

div.koTables_table table {
    margin: 0px;
}

JavaScript

/* BEGIN test data */

// Simulate server side list of item.
var serverData = [{name:'a'},{name:'b'},{name:'c'},{name:'d'},{name:'e'},{name:'f'},{name:'g'}];

/* END test data */

function PageViewModel() {
    var self = this;
    
    self.name = ko.observable('');
    
    self.tblSelected = new TableViewModel({
        aPageSizes: [
            new TableLengthViewModel('5', 5),
            new TableLengthViewModel('10', 10),
            new TableLengthViewModel('All', 0)
        ],
        iPageSize: 5,
        sHeaderTemplate: 'selected-th-template',
        sRowTemplate: 'selected-td-template',
        fnGetEntries: function (skip, take, fnCallback) {
            // Simulate get from server side (normally an AJAX query)
            var viewData = serverData.slice(skip, skip + take);
            
            // Map to array of objects expected by sRowTemplate
            var aoData = ko.utils.arrayMap(viewData, function (oData) {
                return {
                    name: oData.name,
                };
            });
            
            // Let the table know the new state of the server
            fnCallback(aoData, serverData.length, serverData.length, skip);
        },
        fnAddEntry: function (koContext) {
            // Simulate add to server side (normally an AJAX query)
            serverData.push({name: koContext.name()});
            
            // Clear name for new data entry
            koContext.name('');
        },
        fnDelEntry: function (koContext) {
            // Simulate remove from server side (normally an AJAX query)
            serverData = $.map(serverData, function (existing) {
                if (existing.name != koContext.name) {
                    return existing;
                } else {
                    return null;
                }
            });
        }
    });
        
    self.tblSelected.getEntries();
}
	
$(function () {
    ko.applyBindings(new PageViewModel());
});

/* BEGIN koTables.js...