How To Add Datatables To Webpacker In Rails

Datatables in Rails and Webpacker

This is a documentation of using datatables with the latest version of Rails (6.0 at the time of writing) that uses webpacker as the default Javascript compiler.

I found some difficulty in looking for documentation of integrating this in the new Rails away from the lands of Sprocket.

Hopefully this can help you and my future self when I come back to understand what I did to make my codes work instead of leaving it to God.

Only God Knows | Vic-l

Datatables and custom styling

Datatables ship with its core files and some default styling packages with major CSS framework like Bootstrap and Foundation. Taking Bootstrap 4 as the example framework, install the packages below using yarn.

"datatables.net": "^1.10.19",
"datatables.net-bs4": "^1.10.19",

These are the latest versions at the time of writing. They will be added to the package.json file.

Require Datatables

In your javascript file (place it in application.js for now), require the file and initialize datatables.

require("datatables.net")
require('datatables.net-bs4')
require("datatables.net-bs4/css/dataTables.bootstrap4.min.css")

const dataTables = [];

document.addEventListener("turbolinks:load", () => {
  if (dataTables.length === 0 && $('.data-table').length !== 0) {
    $('.data-table').each((_, element) => {
      dataTables.push($(element).DataTable({
        pageLength: 50
      }));
    });
  }
});

document.addEventListener("turbolinks:before-cache", () => {
  while (dataTables.length !== 0) {
    dataTables.pop().destroy();
  }
});

Let me explain what each line does.

On line 1, we import the core datatables js files. These js files adds the standard search and sorting functions of datatables as well as wire up any of your custom configurations.

On line 2, the javascript that will work with Bootstrap 4 elements. It will add elements to the web page for, for example, the pagination feature using the common Bootstrap classes like row and col-*.

On line 3, it imports the custom css file that are required by the datatables JavaScript function but are not present in default Bootstrap stylings. Yes, we are importing the CSS files in a javascript file. Webpack will compile this JavaScript file into the public/packs folder and take care of loading the css into the webpage albeit via javascript. Note that if you set the extract_css option as true in the webpacker configuration, it will instruct webpacker to compile the css into a standalone file, instead of loading it as part of the Javascript code. Hence, you will need to rely on stylesheet_pack_tag to load the css file in the page for the styling to work.

Line 5 is where we declare a datatables array variable to be accessed within this module that is this script. This is a critical step for DataTables to play well with Rails in a turbolinks powered environment. The role of this variable is to store all instances of the tables that have been initialized.

The next 2 blocks of code add 2 listeners to the DOM.

The first triggers the dataTable() function on the desired elements that bear the class data-table. This sets up the pagination, search, sort etc functionalities that make datatables so powerful and simple on your table element. The event this occurs on is turbolinks:load, which is when the url changes and the page loads. Each element is initialized and stored in the dataTables array variable. The 2nd listener will reference them.

The second listener will destroy each of the dataTable instance that are stored in the namesake variable, if any is present. It is triggered during the turbolinks:before-cache event, which takes place when the page navigates away. This step is crucial to remove the elements that were added when the datatables script is evaluated, like the search bar and the pagination elements. If this is not done, there will be extra elements appearing on the webpage when the user navigates back through the browser history as mentioned in this Github issue.

NOTE that it is important NOT to name the class of your elements as “dataTable” as they will get destroyed in the process. If that happens, when the user navigates forward and back again or vice versa, the element will not be picked up and the dataTable() function will not be executed. Kudos to Philip for his comment.

Optimizing

= javascript_pack_tag 'custom/datatables', 'data-turbolinks-track': 'reload'
= stylesheet_pack_tag 'custom/datatables'

Not every page has a table that you will like to initialize the datatable functionalities on. You should only require this in pages that require the code to be executed. In this way, the initial load time of your page will be reduced by not downloading the extra files that you will not use and affect the page speed of innocent pages.
This means downloading 2 files instead of one which can affect page speed due to having to make 2 request instead of 1. However, the resultant overheads from the http requests are unavailing considering these are javascript files that are not render-blocking resources and they can be loaded asynchronously to mitigate it.
Put the above code snippet in another js file in the app/javascript/packs. Webpacker will pick up this file as another entry point and compile the js asset that you can add separately.
Call this js file in the page that require it as such:

Once again, you will find stylesheet_pack_tag useful only if you have enabled extract_css in the webpacker configuration. It will be responsible to load the compiled (or ‘extracted’ in this context) css file.

Playing Well With Turbolinks

# application.html.slim
head
  = yield :javascript_in_head
body
  = yield

# specific/page.html.slim
body
  - content_for :javascript_in_head do
    = javascript_pack_tag 'my-datatables-scripts', 'data-turbolinks-track': 'reload'

Be careful of where you load this javascript file. Make sure to load it in the head html element tag because turbolinks will only handle the javascript files loaded in the head and not the body html element tag.
To do this in the page, use the content_for helper.

Rails will insert the javascript file in the head section at line 3 the for the given page in the head section of the page’s layout, ensuring that turbolinks perform hooks on the javascript file as well.

2 thoughts on “How To Add Datatables To Webpacker In Rails

  1. This doesn’t appear to work for me. Using the browser’s back and forward buttons doesn’t work because doing the datatables.destroy() call REMOVES the dataTable class from the element. I use another class to indicate which table is a datatable. That won’t get removed.

    Also worth noting that I don’t think your code will work if there is more than 1 datatable on a page.

    1. Hi Philip,

      You’re right. Thanks for pointing it out!
      I will improve on it when I have time on my hands.

      PS. Thanks for reading the article.

Leave a Reply

Your email address will not be published. Required fields are marked *