Learn How To Build a Real-time filtering table in Splunk: Part 2

It’s pretty simple to create a table in Splunk. By default, Splunk needs to refetch the data in order to filter it down. However, what if you had a set of data and you wanted to easily filter that table in real-time? This tutorial will take you through step-by-step on how to do this. The second portion of this will cover how to add the filtering functionality to what we have built in the first.



In part 1 we covered the basics of creating an app through the Splunk Web Framework; I demonstrated how to create custom Django template tags for both the input field and table; and then added rendering functionality of those template tags with the help of Splunk’s JS stack.

If, by chance, you already know how to do all of that, or you just want the end result from Part 1, feel free to download the app here

If you want to watch the Screencast for this, go here.

Let’s start by picking up where we left off and begin by adding filter functionality to the table.

Part 1: Sending data between modules

What we want is for the data in our table to filter down as the user types in the filter field. The first step is to add a reference of the table module in our input field. Since all of our rendering and logic is handled through our JavaScript modules, we will add this functionality in there.

Open up filterinput.js and modify the file by adding in the highlighted areas:

// Custom view tutorial
define(function(require, exports, module) {
    var _ = require('underscore');
    var Backbone = require("backbone");
    var SimpleSplunkView = require('splunkjs/mvc/simplesplunkview');

    /* Create a simple backbone view that will be used for our filter field */
    var FilterInput = Backbone.View.extend({
        el: '#filterinput',
        //add an events method so that everytime we 'keyup' in the field
        //it will trigger the 'pushValue' method
        events: {
            'keyup input#filterField' : 'pushValue'
        },
        initialize: function() {
            //define the template we want to use for this --
            //this is defined in the 'block js' of home.html
            this.template = _.template($('#filterFieldTemplate').html());
            this.render();
        },
        //this defines a new instance of a FilterTable and pushes our
        //filter value to it' filterTable method
        pushValue: function() {
            var table = new FilterTable();
            //send the value of the filter input to the filter
            //method inside our table module
            table.filter(this.$el.find('input').val());
        },
        //render the input
        render: function() {
            this.$el.html(this.template());
            return this;
        }
    });

    return FilterInput;

});

Essentially, we want this view to listen for a keyup event and then trigger the pushValuemethod to take the input’s value and push it to our table.

We still need to add a filter method to our table module to catch the input values, which we will use to filter the actual table. Otherwise, if we start typing in the fields now, we’ll get an error in the console: Uncaught TypeError: undefined is not a function

Now open up filtertable.js and add the following highlighted code:

define(function(require, exports, module) {
    var _ = require('underscore');
    var mvc = require('splunkjs/mvc');
    var SimpleSplunkView = require('splunkjs/mvc/simplesplunkview');

    var DummyTable = SimpleSplunkView.extend({
    //class to provide this $el
    className: "dummytable",
    options: {
        data: "results"
    },
    filter: function(val) {
        console.log(‘My Filter Value is: ’, val);
    },

//… rest of code removed for brevity

Now, if you go back to the browser, refresh the page, and open up your console window, you should see output for every character you type.

Great. Now that we have our table registering every keyup event, we need to actually filter our table.

Part 2: Filter our table

Since we know this is working, we can remove our console.log() from our filter()method and replace it with the following:

//split value entered into filter text input
var data = val.split(" ");

//find the rows in the table -- exclude the header row
var tableRows = $('#dbetable').find('tr.body');
//show all table rows if there is no filter
if(val == "") {
    tableRows.show();
    return;
}
tableRows.hide();

//begin filter process
tableRows.filter(function (i, v) {
    var row = $(this);
    //loop through each row of the table to find matching terms
    for (var d = 0; d < data.length; ++d) { 
        //here we utilize the custom icontains expression we 
        //defined above 
        if (row.is(":contains('" + data[d] + "')")) { 
            //if a match is found -- return true 
            return true; 
        } 
    } //otherwise nothing is found, so we return false return false; 
});
//show the rows that match. 
.show();

Here, all we are doing is checking if the value provided from our input is empty. If it is, then we do nothing, otherwise we begin the filtering process. So, if we go back to the browser and refresh the page and start typing the list, it should start to filter in real-time. The only problem is that it isn’t case insensitive. Typing in ALCASAR and alcasar are registered as two completely different things, but there is a way around this. Go ahead and enter the following code at the very top of our filter() method:

jQuery.expr[':'].icontains = function(a, i, m) { 
    return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};

Credit goes to user ‘Highway of Life’ on StackOverflow for this solution (http://stackoverflow.com/questions/8746882/jquery-contains-selector-uppercase-and-lower-case-issue)

Then, in our tableRows.filter() method find if (row.is(":contains('" + data[d] + "')")) { and change the :contains part to :icontains

What we’ve done here is to define a new jQuery expression called icontains, which will make our filtering case-insensitive. Now, when we filter our table it no longer matters if it’s uppercase or lowercase.

At this point, the table should completely filter based off the input you provide - congratulations on building a real-time filtering table in Splunk!

Part 3: Final notes

We are doing some heavy manipulation on the DOM, so be careful of how many results you are returning. You probably want to test it out based on your specific needs. However, if you return 10,000 results, that could become an awfully heavy burden on your browser, since it essentially needs to redraw the table with keyup value.

Another option is to add a filter button and only filter the results when you click on the button, thus reducing the amount of times it needs to be redrawn.

Also, this doesn’t take into account spacing, so if you type wordpress and then wordpress and a space plus another word, it's not going to filter it exactly. However, for the purpose of filtering down for specific terms, this works well.

Feel free to download the final app here plus leave any comments you may have below.




Close off Canvas Menu