All Apps and Add-ons

Why doesn't this JavaScript work to apply a click event to the Water Gauge Custom Viz?

Path Finder

As a followup to "Water Gauge visualization Drilldown??"

Why would this code not apply the click event to my dashboard when it loads? If I run the JavaScript directly in the browser console, the click event is attached, and all is well.

The idea behind the JavaScript is that it will automatically apply a click event to every Water Gauge visualization on the dashboard as long as a drilldown option is added. My theory is that the jQuery that looks for the visualizations is firing too early (before the DOM is loaded), but I don't know of another way to grab the elements without hardcoding, as outlined in the above referenced question.

Dashboard:

<dashboard script="water_gauge_drilldown.js">
  <label>water gauge test</label>
  <row>
    <panel>
      <viz type="TA-ctl_splunk_it_one_viz.water_gauge">
        <search>
          <query>| makeresults | eval hi=55 | fields hi</query>
          <earliest>0</earliest>
          <latest></latest>
        </search>
        <option name="TA-ctl_splunk_it_one_viz.water_gauge.drilldown">http://google.com</option>
      </viz>
    </panel>
  </row>
</dashboard>

Note the required "drilldown" option entry in the Water Gauge XML to define the URL:

<option name="<viz_app>.water_gauge.drilldown">url_to_destination</option>

If the option is not found, the JavaScript will just return false and no action will be taken. Notice that this option is customized to my environment and may throw an error if it is not updated to match your environment.

JavaScript:

var components = [
      "splunkjs/ready!",
      "splunkjs/mvc/simplexml/ready!",
      "jquery"
];
require(components, function(
  mvc,
  ignored,
  $
) {
  $('.splunk-water-gauge').click(function(el) { 
    parent_el = $(this).parents('div[class^="dashboard-element viz"]')[0].id;
    viz_details = mvc.Components.getInstance(parent_el);
    if (typeof(parent_el) == 'undefined') { 
        return false; 
    }
    var url = viz_details.options.reportContent["display.visualizations.custom.TA-ctl_splunk_it_one_viz.water_gauge.drilldown"];
    if(typeof(url) == 'undefined') {
        return false;
    }
    window.open(url,'_blank');
  });
});
0 Karma
1 Solution

Path Finder

After much research and trial & error, I believe the answer to this question is: Because the elements have not finished loading when this JavaScript code is run.

I tried several ways to work around this, including:

$(document).ready(function(){
$(document).bind("PageReady", function() {

And a few others.

But none of these methods ran after the Water Gauge element was created - likely because the visualization itself is built with JavaScript. I ended up wrapping the whole thing in a "setTimeout" block with a wait of 10s. This is a terrible hack, but it's the only way I could figure out to run the script after the water gauge was done loading.

I also attempted to use the native MVC click method instead of jQuery, but could not get the click event to fire. However, I did work around the hardcoded "options" variable, and now read it no matter where the Water Gauge lives in Splunk. Here is the code I finally ended up using:

setTimeout(function(){
    var components = [
          "splunkjs/ready!",
          "splunkjs/mvc/simplexml/ready!",
          "jquery",
          'splunkjs/mvc/utils'
    ];
    require(components, function(
      mvc,
      ignored,
      $,
      utils
    ) {
        $('.splunk-water-gauge').unbind();
        $('.splunk-water-gauge').click(function(el) {
            var re=/([\$].+?[\$])/g
            var url;
            var tokens = mvc.Components.get("submitted");
            parent_el = $(this).parents('div[class^="dashboard-element viz"]')[0].id;
            if (typeof(parent_el) == 'undefined') { 
                return false; 
            }
            viz_details = mvc.Components.getInstance(parent_el);
            var optionsArray = viz_details.options.reportContent;
            getOptionsKeys = Object.keys(optionsArray);
            getOptionsKeys.forEach(function(item) {
                if(item.indexOf("drilldown") != -1) {
                    url=optionsArray[item];
                }
            });
            if(typeof(url) == 'undefined') {
                return false;
            }
            var tokensArray=url.match(re);
            $(tokensArray).each(function(i,token) {
                clean_token=token.replace(/\$?/g,"");
                var tokenValue = tokens.get(clean_token);
                url=url.replace(token,tokenValue);
            });
            utils.redirect(url, false, "_blank");
        });
    });
}, 5000);

Edited to add token handling.

View solution in original post

0 Karma

Path Finder

After much research and trial & error, I believe the answer to this question is: Because the elements have not finished loading when this JavaScript code is run.

I tried several ways to work around this, including:

$(document).ready(function(){
$(document).bind("PageReady", function() {

And a few others.

But none of these methods ran after the Water Gauge element was created - likely because the visualization itself is built with JavaScript. I ended up wrapping the whole thing in a "setTimeout" block with a wait of 10s. This is a terrible hack, but it's the only way I could figure out to run the script after the water gauge was done loading.

I also attempted to use the native MVC click method instead of jQuery, but could not get the click event to fire. However, I did work around the hardcoded "options" variable, and now read it no matter where the Water Gauge lives in Splunk. Here is the code I finally ended up using:

setTimeout(function(){
    var components = [
          "splunkjs/ready!",
          "splunkjs/mvc/simplexml/ready!",
          "jquery",
          'splunkjs/mvc/utils'
    ];
    require(components, function(
      mvc,
      ignored,
      $,
      utils
    ) {
        $('.splunk-water-gauge').unbind();
        $('.splunk-water-gauge').click(function(el) {
            var re=/([\$].+?[\$])/g
            var url;
            var tokens = mvc.Components.get("submitted");
            parent_el = $(this).parents('div[class^="dashboard-element viz"]')[0].id;
            if (typeof(parent_el) == 'undefined') { 
                return false; 
            }
            viz_details = mvc.Components.getInstance(parent_el);
            var optionsArray = viz_details.options.reportContent;
            getOptionsKeys = Object.keys(optionsArray);
            getOptionsKeys.forEach(function(item) {
                if(item.indexOf("drilldown") != -1) {
                    url=optionsArray[item];
                }
            });
            if(typeof(url) == 'undefined') {
                return false;
            }
            var tokensArray=url.match(re);
            $(tokensArray).each(function(i,token) {
                clean_token=token.replace(/\$?/g,"");
                var tokenValue = tokens.get(clean_token);
                url=url.replace(token,tokenValue);
            });
            utils.redirect(url, false, "_blank");
        });
    });
}, 5000);

Edited to add token handling.

View solution in original post

0 Karma