Knockout DataTable

Knockout DataTable Demo

Simple example

S'pose we wanted to display a table of cities. Just create a view model for the data:

class City

  constructor: (@view, row) ->
    @population  = ko.observable row.population
    @countryName = row.country_name
    @cityName    = row.city_name

class @CitiesModel

  constructor: ->

    tableOptions =
      recordWord:       'city'
      recordWordPlural: 'cities'
      sortDir:          'desc'
      sortField:        'population'
      perPage:          15
      unsortedClass:    'glyphicon glyphicon-sort'
      ascSortClass:     'glyphicon glyphicon-sort-by-attributes'
      descSortClass:    'glyphicon glyphicon-sort-by-attributes-alt'

    @table = new DataTable [], tableOptions
    @table.loading true

    req = new XMLHttpRequest()
    req.open 'GET', '/api/cities', true

    req.onload = =>
      if req.status >= 200 and req.status < 400
        response = JSON.parse req.responseText
        rows = response.results.map (row) => new City @, row
        @table.rows rows
        @table.loading false
      else
        alert "Error communicating with server"
        @table.loading false

    req.onerror = =>
      alert "Error communicating with server"
      @table.loading false

    req.send()

    ko.applyBindings @

And a table, like so:

<div data-bind="with: table">
  <div class="pull-right">
    <strong>Results per page</strong>
    <select data-bind="options: [10,25,50], value: perPage"></select>
  </div>
  <input type="text" data-bind="textInput: filter" placeholder="Search"/>
  <table class="table table-striped table-bordered">
    <thead>
      <tr>
        <th style="width: 34%;" data-bind="click: toggleSort('cityName')" class="sortable">
          City
          <i data-bind="css: sortClass('cityName')"></i>
        </th>
        <th style="width: 33%;" data-bind="click: toggleSort('countryName')" class="sortable">
          Country
          <i data-bind="css: sortClass('countryName')"></i>
        </th>
        <th style="width: 33%;" data-bind="click: toggleSort('population')" class="sortable">
          Population
          <i data-bind="css: sortClass('population')"></i>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr data-bind="visible: showNoData">
        <td colspan="3" class="aligncenter">
          This table has no data.
        </td>
      </tr>
      <tr data-bind="visible: showLoading">
        <td colspan="3" class="aligncenter">
          <i data-bind="css: {'icon-spin': showLoading}" class="icon-spinner"></i>
          Loading data...
        </td>
      </tr>
      <!-- ko foreach: {data: pagedRows, as: '$row'}  -->
      <tr>
        <td data-bind="text: $row.cityName"></td>
        <td data-bind="text: $row.countryName"></td>
        <td data-bind="text: $row.population"></td>
      </tr>
      <!-- /ko -->
    </tbody>
  </table>
  <span data-bind="text: recordsText" class="label label-info pull-right"></span>
  <div data-bind="visible: pages() > 1">
    <ul class="pagination">
      <li data-bind="css: leftPagerClass, click: prevPage">
        <a href="#">&laquo;</a>
      </li>
      <!-- ko foreach: {data: (new Array(pages()))} -->
      <li data-bind="css: $parent.pageClass($index() + 1)">
        <a href="#" data-bind="text: $index() + 1, click: $parent.gotoPage($index() + 1)"></a>
      </li>
      <!-- /ko -->
      <li data-bind="css: rightPagerClass, click: nextPage">
        <a href="#">&raquo;</a>
      </li>
    </ul>
  </div>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function(){
  new CitiesModel();
});
</script>

Result:

Results per page
City Country Population
This table has no data.
Loading data...

Example without sorting

Results per page
City Country Population
This table has no data.
Loading data...

Options

When instanciating with new DataTable you have can pass in the following options as the second parameter:

recordWord
The name of your rows. In the case above, we used city. Default: record
recordWordPlural
The plural name of your rows. Since we used city as our recordWord, we used cities for recordWordPlural. Default: recordWord + 's'
sortDir
The initial sorting direction for the table. Default: 'asc'
sortField
The initial sorting column for the table. As of v0.5.0, this setting is optional and the order of table.rows will be maintained and sorting will be disabled.
perPage
Integer indicating the number of rows to be shown per page. Default: 15
unsortedClass
descSortClass
ascSortClass
The classes given to the icons in the th elements indicating the direction of sorting. Set to '' if you would rather have no icons. Default: '' for each

Additionally, you can define the match function on the row class, and the datatable will use it for filtering. If left undefined (as in the example above), the DataTable will automatically search all columns defined on the row. E.g:

row.match:
(filter) ->
  @population().toLowerCase().indexOf(filter) >= 0 or
  @countryName .toLowerCase().indexOf(filter) >= 0 or
  @cityName    .toLowerCase().indexOf(filter) >= 0

Further Usage

Knockout DataTable comes packaged with some advanced filtering. Below is a list of example search terms and the results returned.

cityName:atlanta
Results with 'atlanta' in cityName (case insensitive)
cItYnAmE:aTlAnTa
Results with 'atlanta' in cityName (case insensitive)
countryName:United cityName:L
Results with 'united' in countryName and 'l' in cityName (case insensitive)

Note: as of right now, there is no built-in support for multi-word searching with ':'-delimeted searching

countryname:japan 6
Results with 'japan' in countryName and '6' somewhere in one of the columns (case insensitive)