Dashboards & Visualizations
Highlighted

How to have one or more Pulldown or TextField selections be sticky across all the views in an app

SplunkTrust
SplunkTrust

This is a question that comes up once in a while so I thought I'd write it up as a sort of master-answer.

Say I have several different views in my app that all have the same set of Pulldowns (or TextField) modules at the top. When a user picks a value in one or more of these form elements, I want that value to stick with them even if they just randomly click away to one of the other views using the app navigation. Can this be done?

In other words I'm not talking about maintaining the selection through a drilldown click, but rather if the user uses the app navigation menu to go to a different page in the app, that new page has these same form elements there, I want the same elements from the Pulldown menu to be selected when the next page loads.

And the question is - how to do this.

Tags (1)
Highlighted

Re: How to have one or more Pulldown or TextField selections be sticky across all the views in an app

SplunkTrust
SplunkTrust

This is actually quite difficult to do, and it requires custom Javascript. Furthermore to do it correctly and carefully, that custom code has to be quite careful and therefore quite long and complex. However the site seems to lack a definitive answer and it comes up once in a while so here we go.

Here is how you would set this up with the Sideview Utils modules Pulldown and CustomBehavior. The basic idea is to actively rewrite all the relevant links on the page so as to preserve the most recently selected value(s) in all of those links, and then rely on the URLLoader module in all of these views to load the values from the URL and prepopulate the Pulldowns/TextField modules in each target view as the user clicks around.

Part 1) Download and install a recent copy of Sideview Utils from the sideview site ( http://sideviewapps.com/apps/sideview-utils )

Part 2) XML that sets up a working testcase:

<view autoCancelInterval="90" isVisible="False" onunloadCancelJobs="true" template="dashboard.html" isSticky="False">
  <label>Testcase for Link-rewriting customBehavior</label>
   <module name="AccountBar" layoutPanel="appHeader" />
  <module name="AppBar" layoutPanel="appHeader" />
  <module name="SideviewUtils" layoutPanel="appHeader"></module>

  <module name="Message" layoutPanel="messaging">
    <param name="filter">*</param>
    <param name="maxSize">2</param>
    <param name="clearOnJobDispatch">False</param>
  </module>

  <module name="HTML" layoutPanel="viewHeader">
    <param name="html"><![CDATA[
    <h1>Testcase for Link-rewriting customBehavior</h1>
    ]]></param>
  </module>

  <module name="URLLoader" layoutPanel="panel_row1_col1" autoRun="True">
    <param name="keepURLUpdated">True</param>

    <module name="Pulldown" group="static config">
      <param name="name">test1</param>
      <param name="label">test1</param>

      <param name="staticOptions">
        <list>
          <param name="label">fooLabel</param>
          <param name="value">fooValue</param>
        </list>
        <list>
          <param name="label">barLabel</param>
          <param name="value">barValue</param>
        </list>
        <list>
          <param name="label">bazLabel</param>
          <param name="value">bazValue</param>
        </list>
      </param>

      <module name="CustomBehavior">
        <param name="customBehavior">addSelectionToAllLinksOnPage</param>
      </module>

      <module name="HTML">
        <param name="html"><![CDATA[

         <p>
         selected value is:<br>
          $test1$
         </p>

         Note that the customBehavior will only rewrite links that are in the app navigation menus. So barring some modification to the JS, the following links will NOT get the special href-rewriting behavior. <br>

         <a href="testcases_for_link_rewrite_custom_behavior">link1</a><br>
         <a href="/app/sideview_utils/testcases_for_link_rewrite_custom_behavior">link2</a>

        ]]></param>
      </module>
    </module>
  </module>
</view>

Part 3: The JS that you put in application.js

if (typeof(Sideview)!="undefined") {

    /*
     * advanced customBehavior and other custom code to implement a feature 
     * whereby several views can have one or more pulldowns,  where even if 
     * the user navigates away from the view to another random view,  if the 
     * pulldown(s) are present in the new view,  the selected value is always
     * passed from the first view to the second.  Again, this behavior happens
     * even if the user uses the app navigation bar to switch views. 
     * As such the implementation involves actively rewriting the href 
     * attributes of the actual link elements in the HTML.
     */
    var fieldsToPreserve = ["test1", "host"];
    function rewriteLinks(argDict) {
        // We start by getting a collection of all the link elements within the
        // AppBar module (aka the app navigation menus).
        var linksToRewrite  = $("div.AppBar a");

        // depending on version the submenus of the AppBar may not actually be
        // in the AppBar module's container div.
        var splunkVersion = Splunk.util.getConfigValue("VERSION_LABEL");
        if (Sideview.utils.compareVersions(splunkVersion,"4.3") > -1) {
            var extraMenuLinks = $("body .outerMenuWrapper .innerMenuWrapper a");
            linksToRewrite = linksToRewrite.add(extraMenuLinks);
        }

        linksToRewrite.each(function(i) {
            var a = $(this);
            var href = a.attr("href");
            // dont mess with these links. They might have their own args.
            if (a.text() == "Help" || a.text() == "About" || href.charAt(0)=="#") return true;

            // dont mess with these links either. Especially with the patch to
            // get all the links that 4.3 puts at the bottom of the page, we're
            // going to be iterating through links that are from a number of 
            // other modules that have action menus.
            if (href.substring(0,11)=="javascript:") return true;

            // nor do we touch links that go to other apps.
            if (href.indexOf("/app/" + Splunk.util.getCurrentApp() + "/")==-1) return true;

            var newArgDict = {};
            if (href.indexOf("?")!=-1) {
                // make sure to preserve any existing args (uncommon but important).
                var existingArgDict = Sideview.utils.stringToDict(a.attr("href").substring(href.indexOf("?")+1));

                // well not all of them. We're about to write new definitive 
                // values for our "fieldsToPreserve" ones, so we throw the 
                // old values away. 
                for (var i=0,len=fieldsToPreserve.length;i<len;i++) {
                    delete existingArgDict[fieldsToPreserve[i]];
                }
                $.extend(argDict,existingArgDict);
                // clean all the old qs args off the string.
                href = href.substring(0,href.indexOf("?"));
            }
            href += "?"+Sideview.utils.dictToString(argDict);
            $(this).attr("href",href);
        });

    };


    Sideview.utils.declareCustomBehavior("addSelectionToAllLinksOnPage", function(customBehaviorModule) {
        customBehaviorModule.onContextChange = function() {
            var context = this.getContext();
            var args ={};
            for (var i=0,len=fieldsToPreserve.length;i<len;i++) {
                var f = fieldsToPreserve[i];
                // get the untemplated value if there is one.
                var value = context.get(f + ".rawValue") || context.get(f);
                if (value) {
                    args[f] = value;
                }
            }
            // an option you might also need is to preserve the current 
            // timerange as seen from the customBehavior module.
            //var range = context.get("search").getTimeRange();
            //if (range.getEarliestTimeTerms()) args["earliest"] = range.getEarliestTimeTerms();
            //if (range.getLatestTimeTerms())   args["latest"]   = range.getLatestTimeTerms();
            rewriteLinks(args);
        }.bind(customBehaviorModule);
    });

    // this rewrites the page links initially, so that they're set before even 
    // the first context push hits our CustomBehavior.  We have to wait until
    // allModulesInHierarchy is fired or else the AppBar's menus wont exist.
    $(document).bind("allModulesInHierarchy", function() {
        var qsDict = Sideview.utils.stringToDict(document.location.search.substring(1));
        rewriteLinks(qsDict);
    });
}

Note: if you're setting up this working testcase to run locally make sure to put the view into the same app as the Javascript. Also make sure to clear your cache so that you reload the new application.js.

Highlighted

Re: How to have one or more Pulldown or TextField selections be sticky across all the views in an app

SplunkTrust
SplunkTrust

Note: Don't let this very complicated custom code make you think that Pulldown module is difficult to use. It's actually much much simpler to use than the equivalent core modules and here's a screencast to prove it to you - http://www.youtube.com/watch?v=fkXBgkwZoEQ

0 Karma
Highlighted

Re: How to have one or more Pulldown or TextField selections be sticky across all the views in an app

Builder

thank you Nick,Really helped me.

is it possible to add a table name in side view table modules? or do i have to use html panel for the same?
Thank you

0 Karma
Highlighted

Re: How to have one or more Pulldown or TextField selections be sticky across all the views in an app

SplunkTrust
SplunkTrust

Assuming you mean adding some visible header text just above the Table? If so then indeed you should just use an HTML module. Generally such text will be above the Pager module, so even if there was a built-in header in the Table, it would be of little use.

Highlighted

Re: How to have one or more Pulldown or TextField selections be sticky across all the views in an app

Builder

Ya, you are right nick,
in simple XML we have an option like

 THREAD DURATION:

this is what i meant

0 Karma