Integrating jQuery DataTables Into Splunk: Tutorial Part 3

This blog-screencast tutorial covers how to integrate jQuery DataTables into Splunk. Data tables are a great way to easily integrate awesome features into simple HTML tables. After following along with this tutorial, the final result will be a table that you can filter down and integrate into your own Splunk environment and do some cool stuff with it.



Setting Up the Template

Now that we know we're passing the data successfully into the view, we want to actually render something out to the DOM. So, we need to set up a template to attach our view to. In this part of the tutorial, we're going to start working on building out the templates and loading those templates in from external files and then using those templates inside of our data table view. 

Inside of the components folder create a new folder called templates. In the templates folder create a file called data_table.html and put the following:

<script type="text/x-template" id="data-table-template">
    <table cellpadding="0" cellspacing="0" border="0"
           class="table tale-chrome table-striped display dataTable"
           id="table">
        <thead>
            <tr role="row">
                <th>Time</th>
                <th>Message</th>
            </tr>
        </thead>
        <tbody>
        <body>
    </table>
</script>

This sets up the basics for our table and will apply the appropriate styling to it so it matches the look of other tables in Splunk.

Next, below the <script /> template tag we will add a wrapper div in which will we append our table.

<div id="data-table-wrapper"></div>

Loading in the Template Files

Before we do anything we will need to use require.js’ text.js in order to load and render the templates.

Download a copy of text.js here: https://github.com/requirejs/text/blob/master/text...

Once you’ve downloaded it, place it inside of your components folder. We will then reference it inside of the DataTableView.js file.

Inside of DataTableView.js add the following in the require.config’s path object:

text: "../app/<your_app_name>/components/text",
dataTableTemplate: '../app/<your_app_name>/components/templates/data_table.html'

Then in the define function load in the template using the text! argument:

'text!dataTableTemplate',

And finally, make a reference to the template in the function parameter:

function(mvc, ignored, _, Backbone, DataTables, DataTableTemplate, $) {

So, in the end you will have something that looks like this:

require.config({
    paths: {
        datatables: "../app/datatable_fun/components/DataTables-1.10.12/media/js/jquery.dataTables",
        bootstrapDataTables: "../app/datatable_fun/components/DataTables-1.10.12/media/js/dataTables.bootstrap",
        text: "../app/datatable_fun/components/text",
        dataTableTemplate: '../app/datatable_fun/components/templates/data_table.html'
    },

    shim: {
        'bootstrapDataTables': {
            deps: ['datatables']
        }
    }
});

define([
    'splunkjs/ready!',
    'splunkjs/mvc/simplexml/ready!',
    'underscore',
    'backbone',
    'datatables',
    'text!dataTableTemplate',
    'jquery'
], function(mvc, ignored, _, Backbone, DataTables, DataTableTemplate, $) {

We will need a div to render the table into. So, go to your dashboard and edit the source and add the following at the bottom: 

  <row>
    <html>
      <div id="tableWrapper"></div>
    </html>
  </row>

Inside of index.js add a reference to the element that our view will use to render our DataTable:

var dataTableView = new DataTableView({
    data: rows,
    el: $("#tableWrapper")
}).render();

Now that we have an element to reference, we can use that inside our render method in the DataTableView.js file:

render: function() {
     console.log('DataTables Data: ', this.data);
     this.$el.html(DataTableTemplate);
}

Note: Moving forward if you make changes to your template, but they don’t show up, you may need to run _bump even if you modified the caching in server.conf earlier. The reason for this is we turned off caching for our JavaScript files but this won’t affect our template files.

Rendering the DataTable

Rendering the DataTable will take a little extra work. First, we will create a new method in our DataTableView.js file called renderDT to handle the rendering of the DataTable. We could put this all in our render method directly, but from a readability standpoint this separation makes more sense.

Open the DataTableView.js file and add the following method about the render method:renderDT: function() { },

renderDT: function() { },

While we’ve already loaded our template file successfully, we still need to render the <script type="text/x-template" id="data-table-template"> portion of the file, as this wont be rendered out by default. In order to do this, first add the following in to the renderDT method:

var DT_Template = $('#data-table-template', this.$el).text();

This is saying that we want to pull the text from the <script type="text/x-template" id="data-table-template"> part of the template.

In order to actually render it into the DOM, we need to add the following:

$("#data-table-wrapper", this.$el).html(_.template(DT_Template, {}));

Looking at the template file, there are two sections:

<script type="text/x-template" id="data-table-template">
   … omitted for brevity ...
</script>

<div id="data-table-wrapper">
   … omitted for brevity ...
</div>

Our code is saying that in our view’s element, which was set earlier as #tableWrapper look for the div ‘data-table-wrapper’ and append the ‘data-table-template’ to it. Using the .html() method ensures that it is rendered as HTML and not text. We also use Underscore’s _.template() method. Lastly, we pass an empty object as the last parameter of the html() method. We will be filling this in a little bit later.

Now we need to build out the DataTable:

this.data_table = $('#table', this.$el).DataTable( {
"iDisplayLength" : 20,        // length of data per page
"bLengthChange" : false,      // would allow users to select page size with dropdown menu
"searching" : true,           // allows users to filter results with a text input
"sDom" : "ftp",               // saying we only want to show the filter input, table and pagination elements
      	"oLanguage": {
"sSearch": "",                // no placeholder text for filter input
"oPaginate" : {
"sPrevious" : "Prev"          // change 'Previous' text to 'Prev'
}
       },
       "bStateSave" : true,          // sets cookie to save table display information
       "aaSorting": [[ 1, "asc" ]],  // controls sorting
       "aoColumns": [
       	null,  // Time Column
             null,  // Message Column
       ]
});

Our code is saying that in our view’s element, which was set earlier as #tableWrapper look for the div ‘data-table-wrapper’ and append the ‘data-table-template’ to it. Using the .html() method ensures that it is rendered as HTML and not text. We also use Underscore’s _.template() method. Lastly, we pass an empty object as the last parameter of the html() method. We will be filling this in a little bit later.

Now we need to build out the DataTable:

this.data_table = $('#table', this.$el).DataTable( {
"iDisplayLength" : 20,        // length of data per page
"bLengthChange" : false,      // would allow users to select page size with dropdown menu
"searching" : true,           // allows users to filter results with a text input
"sDom" : "ftp",               // saying we only want to show the filter input, table and pagination elements
      	"oLanguage": {
"sSearch": "",                // no placeholder text for filter input
"oPaginate" : {
"sPrevious" : "Prev"          // change 'Previous' text to 'Prev'
}
       },
       "bStateSave" : true,          // sets cookie to save table display information
       "aaSorting": [[ 1, "asc" ]],  // controls sorting
       "aoColumns": [
       	null,  // Time Column
             null,  // Message Column
       ]
});

Finally, we need to call the renderDT method inside the render method:

        render: function() {
            console.log('DataTables Data: ', this.data);
            this.$el.html(DataTableTemplate);
            this.renderDT();
        }

When you refresh the dashboard you should see the following:

Fantastic...we’re all done – oh, wait we need our data to actually populate the table. We'll do that next in Part 4!

(Also, here are the links for Part 1 and Part 2, just in case).




Close off Canvas Menu