Skip to content

LumaPictures/meteor-jquery-datatables

Repository files navigation

NOTE This project is no longer maintained. Having a look at meteor-tabular for an actively maintained alternative with automatic serverside publishing.

jQuery DataTables Build Status

Sort, page, and filter millions of records.

Reactively.

This package wraps the powerful and mature DataTables.net jQuery plugin for enhancing HTML tables.

DataTables.net features

  • Variable length pagination
  • On-the-fly filtering
  • Multi-column sorting with data type detection
  • Smart handling of column widths
  • Display data from almost any data source
  • Scrolling options for table viewport
  • Fully internationalisable
  • jQuery UI ThemeRoller support
  • Rock solid - backed by a suite of 2900 unit tests
  • Wide variety of plug-ins inc. Editor, TableTools, FixedColumns and more

Local Example

The first time your run the example app it will take a minute or two to start, this is because the example is writing 100k documents to the Browsers collection as an example dataset. You can change this here.

$ git clone https://github.com/lumapictures/meteor-jquery-datatables
$ cd meteor-jquery-datatables/example
$ mrt add jquery-datatables
$ meteor

Local Tests

$ git clone https://github.com/lumapictures/meteor-jquery-datatables
$ cd meteor-jquery-datatables/example
$ mrt add jquery-datatables
$ meteor test-packages jquery-datatables

Usage

All you have to do is include the datatable component in one of your templates like so:

{{> DataTable browsers }}

Then setup the data in your controller or as template helpers:

Template.<yourTemplate>.browsers = -> return {
  
  # ## Id
  #   * While not required, setting a unique table id makes external manipulation possible through jquery
  id: "my-unique-table-id"
  
  # ## Columns
  #   * Map your dataset to columns you want displayed
  columns: [{
    title: "Engine"
    data: "engine"
  },{
    title: "Browser"
    data: "browser"
  },{
    title: "Platform"
    data: "platform"
  },{
    title: "Version"
    data: "version"
  },{
    title: "Grade"
    data: "grade"
  },{
    title: "Created"
    data: "createdAt"
    mRender: ( data, type, row ) -> return moment( row.createdAt ).fromNow()
  },{
    title: "Counter"
    data: "counter"
  }]
  
  # ## Subscription
  #   * the datatables publication providing the data on the server
  subscription: "all_browsers"
  
  # ## Query
  #   * the initial client filter on the dataset
  query:
    grade: "A"
}

Reactive Query

The query parameter for reactive tables is now reactive ( duh ). My goal was to have the table impose no structure on the query and just use raw mongoDB selector.

The basic idea is that you set a session variable ( or some other reactive datasource ) to your initial query and then use that var as the query parameter for the table component. Whenever the query parm changes the table will automagically rerender using the new query to fetch its dataset.

You can see a basic implementation of this here In the example the table controls just extend the query object with whatever value they are set to. I tried to include examples of all the common control types, but if you think of any that I missed feel free to let me know.

Currently applying the filter can cause a somewhat janky table reload depending on what its contents looks like, this is something I plan on addressing ASAP.

Publishing Data

On the server side, you need to publish the data:

if Meteor.isServer
  RowsTable = new DataTableComponent
    subscription: "rows"
    collection: Rows
  
  RowsTable.publish()

Limit Client Data Access

If you would like to limit the dataset published to the client simply append a query parameter to you the initialization object

if Meteor.isServer
  RowsTable = new DataTableComponent
    
    subscription: "rows"
    
    collection: Rows
    
    # ##### Only return the rows created today
    query:
      createdAt: $gte: moment().startOf( "day").toDate()
  
  RowsTable.publish()

You can also set the query parameter to a function if you require access the this context of the publication for things like user restricted access.

Query functions take the component as a parameter, so you still have access to the component context and all its instance methods.

if Meteor.isServer
  RowsTable = new DataTableComponent
    
    subscription: "rows"
    
    collection: Rows
    
    # ##### Only return rows this user owns
    query: ( component ) ->
        console.log "userId", this.userId
        return { owner: this.userId }
    
    debug: "userId"

  RowsTable.publish()

Event Binding

You can access the datatable after it has been initialized, it is stored in the data context of the instantiated datatable component. However this is not the best way to extend the tables features.

You have 3 main options ( going from simplest to most flexible )

  1. simply attach events via jquery ( you must set id )

{{> dataTable id="example" columns=pages.columns rows=pages.rows }}

$( '#example tbody' ).on 'click', 'tr', ->
  name = $( 'td', @ ).eq( 0 ).text()
  console.log "You clicked on #{ name }'s row"

The major drawback of this method is that you have to track the table state externally. Good for simple events, but I wouldn't recommend it for anything complex.

  1. Attach events through the initialization options

Set options in your controller or via a template helper

options =
  initComplete: ->
    api = @api()
    api.$( 'td' ).click -> api.search( @innerHTML ).draw()

{{> DataTable options=options columns=pages.columns rows=pages.rows }}

Now datatables is handling the data for you. Here is a ton of api method example https://datatables.net/examples/api/

This option will cover most of your use cases.

Styling

This package DOES NOT PROVIDE ANY STYLES OR ASSETS intentionally.

If you would like some help styling datatables you can check out my luma-ui package or the DataTables.net official docs.

Contributing