Knockout Table Paging Binding

Using Knockout to do table Paging

by cjgaudin

HTML

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/base/jquery-ui.css">
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.debug.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout/master/build/output/knockout-latest.debug.js"></script>
<div id="messageLog">
</div>
<div id="filterPanel">
    <h3><a href="#">Filter Panel</a> </h3>
    <div id="filterContainer">
        <div class="first">
            <span>Job#:</span>
            <input type="text" data-bind="value: selectedJobNumber" maxlength="8"/>
        </div>
        <div>
            <span>Title:</span>
            <input type="text" data-bind="value: selectedTitle"/>
        </div>
        <div class="first">
            <span>Categories:</span>
            <select data-bind="options: categoryLookups,
                               optionsCaption: ' ',
                               optionsText: 'Name',
                               value: selectedCategory"></select>
        </div>
        <div>
            <span>Types:</span>
            <select data-bind="options: typeLookups,
                               optionsCaption: ' ',
                               optionsText: 'Type',
                               value: selectedType"></select>
        </div>
        <div>
            <span>Status:</span>
            <select data-bind="options: statusLookups,
                               optionsCaption: ' ',
                               optionsText: 'Status',
                               value: selectedStatus"></select>
        </div>

        <input id="clearFilterButton" type="button" value="clear" />
        <input id="filterButton" type="button" value="filter" />
    </div>
</div>
<div id="projectList">
    <table class="work-table" >
            <thead>
                <tr>
                    <th><a href="#" data-sort-field="JobNumber" data-sort-direction="Desc"...

CSS

/* Table Styling*/
table.work-table {
    border-collapse:collapse;
    border: 1px solid black;
    width: 100%;
}
table.work-table th {
    background-color:lightgray;
    color: black;
    font-weight: bold; 
    font-size: 0.8em;
    border: 1px solid black;
    text-align: center;
}
table.work-table tr:nth-child(even) {
    background-color: rgb(240, 240, 240);
}
table.work-table tr:nth-child(odd) {
    background-color: white;
}
table.work-table tr td {
    border: 1px solid rgb(134, 134, 134);
    text-align: center;
}
table.work-table td.justify-left {
    text-align: left;
}
table.work-table tr.highlightRow {
    cursor: pointer;
}
table.work-table tr.tableDataRow td {
    padding: 3px;
}
table.work-table tr.highlightRow:hover {
    background-color: rgb(241, 255, 219);
}
table.work-table tr.task-complete-row  {
    background-color: rgb(241, 255, 219);
}
table.work-table tr.task-complete-row > td {
    border: 1px solid yellowgreen;
}
table.work-table tr.task-incomplete-row {
    background-color: rgb(255, 227, 227);
}
table.work-table tr.task-incomplete-row > td {
    border: 1px solid red;
}
table.work-table tr.assigned-work-request-row {
    background-color: rgb(252, 240, 231);
}

td > span.tableDescriptionColumn {
    font-style:italic;
    font-size: 0.9em;
    padding-left: 20px;
}
td > span.tableDataColumn, a.edit-comment, a.edit-equipment, a.edit-task {
    font-size: 1.0em;
}
div.pagingContent {
    padding: 10px;
    width: 100px;
    margin: 0 auto;
    text-align: center;
}
div.pagingContent > a {
    padding: 3px;
    font-weight: bold;
    color:rgb(149, 149, 149);
}

a.metro-button {
    font-variant:small-caps;
    font-size: 1.0em;
    font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
    border:1px solid black;
    padding: 3px;
    font-weight: bold;
    width: 150px;
    text-align:center;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    display: block;
    color: black;
    line-height:...

JavaScript

var main = (function (main, $, undefined) {
    var viewModel = main.searchViewModel = main.searchViewModel || {};
    //Default options for this view model
    var options = {
        filterPanelSelector: '#filterPanel',
        filterButtonSelector: '#filterButton',
        clearButtonSelector: '#clearFilterButton',
        messageSelector: '#messageLog',
        dialogSelector: '#selectedProjectContainer',
        baseSearchUrl: null,
        baseLookupUrl: null,
        baseWorkUrl: null
    };

    //---------------PUBLIC FUNCTIONS--------------------
    viewModel.initialize = function (serverModel) {
        viewModel.searchItems = ko.observableArray();
        viewModel.typeLookups = serverModel.Types;
        viewModel.statusLookups = serverModel.Statuses;
        viewModel.categoryLookups = serverModel.Categories;

        viewModel.selectedWorkItem = ko.observable(null);
        viewModel.selectedCategory = ko.observable(null);
        viewModel.selectedStatus = ko.observable(null);
        viewModel.selectedType = ko.observable(null);
        viewModel.selectedJobNumber = ko.observable('');
        viewModel.selectedTitle = ko.observable('');

        //Url binders for the action menu
        viewModel.viewWorkUrl = ko.observable('#');
        viewModel.editWorkUrl = ko.observable('#');

        //Paging Table bindings
        viewModel.pageSize = ko.observable(10);
        viewModel.pageIndex = ko.observable(0);
        viewModel.previousPage = function () {
            viewModel.pageIndex(viewModel.pageIndex() - 1);
        };
        viewModel.nextPage = function () {
            viewModel.pageIndex(viewModel.pageIndex() + 1);
        };
        viewModel.maxPageIndex = ko.computed(function () {
            return Math.ceil(this.searchItems().length / this.pageSize()) - 1;
        }, viewModel);
        viewModel.pagedItems = ko.computed(function () {
            var size = this.pageSize();
            var start = this.pageIndex() * size;
         ...