Dashboards & Visualizations

Access Row Fields in BaseCellRenderer

tkreiner
Explorer

I am working with a custom HTML dashboard. I see how to use the TableView and the BaseCellRenderer together to customize the contents of a given cell in the table. However, when the BaseCellRenderer is called, it appears that I can only access the value of that field. Is there a way that I can reference the values of all the fields in that rows data?

Here is what I'm trying to accomplish...

I have a table displaying three columns of data. I want to add an action to the end of the row that when clicked, will grab the values of those three data columns and push those into a KV Store. I created a dummy field in my search (eval Action=1) so that the table renders an additional column for me to override with the BaseCellRenderer. But the only data I can see in that function is the value of the Action field which is 1. I need to know the values of the 3 other fields of that row.

0 Karma
1 Solution

tkreiner
Explorer

I found an answer to this question from a colleague. The BaseCellRenderer is called sequentially for each column of the output. Therefore, it will touch each cell leading up to the last column where I want to create my action link. Because of this, you can write script for each column to capture that column's value and hold it in a temporary JavaScript variable. When you render the last column, you can pull from the JavaScript variables to the data you need from the record to create the link.

In my example, I was working with ps data from Linux and I needed to capture the HOST, COMMAND and ARGUMENTS fields. In my JavaScript, I first created three global variables:

var rowHost;
var rowCommand;
var rowArguments;

Then my BaseCellRenderer definition looks something like the following:

            // Use the BaseCellRenderer class to create a custom table cell renderer
            var AddMonitorRenderer = TableView.BaseCellRenderer.extend({ 
                canRender: function(cellData) {
                    return true;
                },

                // This render function only works when canRender returns "true"
                render: function($td, cellData) {
                    switch(cellData.field.toUpperCase())
                    {
                        case "HOST":
                            rowHost = cellData.value;
                            break;
                        case "COMMAND":
                            rowCommand = cellData.value;
                            break;
                        case "ARGUMENTS":
                            rowArguments = cellData.value;
                            break;
                        default:
                    }

                    if(cellData.field == "Action") {
                        $td.html('<div align="right"><a href="#" onclick="addMonitor(\'' + escapeJSValue(rowHost) + '\',\'' 
                        + escapeJSValue(rowCommand) + '\',\'' 
                        + escapeJSValue(rowArguments) + '\')">Add to Monitor</a></div>');
                    }
                    else {
                        $td.html(cellData.value);
                    }
                }
            });

This does a couple of things:

  1. The canRender function always returns a value of true. This way, the renderer class will fire for each column of the result set.
  2. In the render function, I test to see which field the renderer is currently running for (HOST, COMMAND, ARGUMENTS) and then I store that column's value in the appropriate global variable.
  3. In the final if statement, if I am in my Action column (this was a dummy value that I added to my search criteria using | eval Action = 1), then I display a link to my addMonitor() function. (NOTE: The escapeJSValue() function is a custom function I have in another part of my code.) If I am not in my Action column, then simply display that column's field value.

I added this cell renderer to my TableView and rendered the table and my action appears and works correctly.

View solution in original post

tkreiner
Explorer

I found an answer to this question from a colleague. The BaseCellRenderer is called sequentially for each column of the output. Therefore, it will touch each cell leading up to the last column where I want to create my action link. Because of this, you can write script for each column to capture that column's value and hold it in a temporary JavaScript variable. When you render the last column, you can pull from the JavaScript variables to the data you need from the record to create the link.

In my example, I was working with ps data from Linux and I needed to capture the HOST, COMMAND and ARGUMENTS fields. In my JavaScript, I first created three global variables:

var rowHost;
var rowCommand;
var rowArguments;

Then my BaseCellRenderer definition looks something like the following:

            // Use the BaseCellRenderer class to create a custom table cell renderer
            var AddMonitorRenderer = TableView.BaseCellRenderer.extend({ 
                canRender: function(cellData) {
                    return true;
                },

                // This render function only works when canRender returns "true"
                render: function($td, cellData) {
                    switch(cellData.field.toUpperCase())
                    {
                        case "HOST":
                            rowHost = cellData.value;
                            break;
                        case "COMMAND":
                            rowCommand = cellData.value;
                            break;
                        case "ARGUMENTS":
                            rowArguments = cellData.value;
                            break;
                        default:
                    }

                    if(cellData.field == "Action") {
                        $td.html('<div align="right"><a href="#" onclick="addMonitor(\'' + escapeJSValue(rowHost) + '\',\'' 
                        + escapeJSValue(rowCommand) + '\',\'' 
                        + escapeJSValue(rowArguments) + '\')">Add to Monitor</a></div>');
                    }
                    else {
                        $td.html(cellData.value);
                    }
                }
            });

This does a couple of things:

  1. The canRender function always returns a value of true. This way, the renderer class will fire for each column of the result set.
  2. In the render function, I test to see which field the renderer is currently running for (HOST, COMMAND, ARGUMENTS) and then I store that column's value in the appropriate global variable.
  3. In the final if statement, if I am in my Action column (this was a dummy value that I added to my search criteria using | eval Action = 1), then I display a link to my addMonitor() function. (NOTE: The escapeJSValue() function is a custom function I have in another part of my code.) If I am not in my Action column, then simply display that column's field value.

I added this cell renderer to my TableView and rendered the table and my action appears and works correctly.

Ayn
Legend

This saved me lots of work and headache, thanks 🙂

0 Karma

chris
Motivator

Hi, i would like to do something very similar. I would like to add checkboxes to every row and then have a button that does a mass update to the kv store. Would you mind sharing the addMonitor function?

0 Karma

bijolianabhi
Engager

Hi @chris , 

Were you able to add checkbox in every row and select all checkbox in table? I am looking for something like that? Would you mind sharing how you did that? 

0 Karma

sundareshr
Legend

May be easier to populate the hidden field with concatenated values in the search that populates the table. Or create a hidden search that gets values from all three cells ($row.<>$) and call outputlookup to update kvstore

tkreiner
Explorer

Thanks sundareshr. I had thought about the concatenated field. It's an ugly way of doing it, but it is possible. I may give that a try. For now, I decided to go the route of using a RowExpansionRenderer and creating an action underneath the row. It adds an extra click, but it does work.

0 Karma
Get Updates on the Splunk Community!

Index This | I am a number, but when you add ‘G’ to me, I go away. What number am I?

March 2024 Edition Hayyy Splunk Education Enthusiasts and the Eternally Curious!  We’re back with another ...

What’s New in Splunk App for PCI Compliance 5.3.1?

The Splunk App for PCI Compliance allows customers to extend the power of their existing Splunk solution with ...

Extending Observability Content to Splunk Cloud

Register to join us !   In this Extending Observability Content to Splunk Cloud Tech Talk, you'll see how to ...