Dashboards & Visualizations

Prevent any processing until Submit button was pressed - with a twist

Ingo
Engager

Hello all,

I've been searching this community up and down and also came of course across @niketnilay  references about it (https://community.splunk.com/t5/Dashboards-Visualizations/Submit-Button-not-working/m-p/387165#M2536...

The all assume that the dashboard/form is "entered" empty. All the sample code I found failed when form already receives values via the URL e.g.

https://community.splunk.com/t5/Dashboards-Visualizations/searchWhenChanged-false-not-honored/td-p/4...

my_form?form.tokDDLogLevel=INFO

    <input type="dropdown" token="tokDDLogLevel" searchWhenChanged="false">
      <label>Select Log Level</label>
      <choice value="INFO">INFO</choice>
      <choice value="ERROR">ERROR</choice>
      <choice value="WARN">WARN</choice>
     <initialValue>$form.tokDDLogLevel$</initalValue>

I have 3 dropdowns and 1 textfield expecting 1 to all 4 values to be modifed. When they get prefilled like this it triggers the immediate execution of my search:

<search> | makeresults | eval field1=$tokDDLogLevel$ field2=$...$...</search>

The <initialValue> as well as the <default> seem to trigger the change event immediately without the submit button.

Another example by @dmarling : https://community.splunk.com/t5/Dashboards-Visualizations/In-a-Simple-XML-dashboard-is-it-possible-t...

<dashboard>
  <init>
    <set token="query">| makeresults count=1 | eval x= "Yes" | table x</set>
  </init>
  <label>demodash</label>
  <fieldset submitButton="true" autoRun="false">
    <input type="dropdown" token="Input1">
      <label>Input1</label>
      <choice value="A">A</choice>
      <choice value="B">B</choice>
    </input>
    <input type="dropdown" token="Input2">
      <label>Input2</label>
      <choice value="C">C</choice>
      <choice value="D">D</choice>
    </input>
  </fieldset>
  <search>
    <query>| makeresults count=1 
| eval search=if("A"=$Input1|s$ AND "C"=$Input2|s$,  "| makeresults | eval x=\"No\" | table x", "| makeresults | eval x=\"Yes\" | table x")
| table search</query>
    <done>
      <condition match="$job.doneProgress$=1">
        <set token="query">$result.search$</set>
      </condition>
    </done>
  </search>
  <row>
    <panel>
      <table>
        <search>
          <query>$query$</query>
        </search>
      </table>
    </panel>
  </row>
</dashboard>

 

Now call this dashboard via e.g. "test?form.Input1=A&form.Input2=D" - The query gets built and executed without pressing the Submit button. 

BTW, I have the same issue for empty forms where some drop downs are set dynamically via searchOnChange. As soon as all fields have values the query is executed automatically.

This seems to be a particular problem when using forms in combination with makeresults + eval causing the autoRun=false being ignored.

 

Is there some JavaScript workaround to prevent the form submission until Submit was actually pressed? 

(am desperate to even consider turning a checkbox somehow into a submit button and then use "makeresult `comment $checkbox_tok$` the submit button somehow - otherwise only clicking checkbox will once again execute makeresult + eval due to the checkbox, not the Submit button <- any idea how to this nasty hack?) 

(Note: using Splunk 7.3.6 which I can't update at the moment)

Thanks guys. Been fighting with this for way too much time already. 😞

 

Labels (3)
0 Karma
1 Solution

dmarling
Builder

Hi @Ingo,

The simplest way to do this with javascript would be to create a button input that on click sets a token that is present in all of your other searches.  You can also do this with simplexml, but it will add the token to the url when they click submit and I'm guessing you don't want that.

The below javascript will set a token defined with a name of "submitbutton" and a value of "*".  This value will only be set when clicking html submit button created in the xml.  In order for this to work you need to add "| search $submitbutton$" anywhere after the first line of your search and it will then prevent the search from running until the button is pushed.

Javascript for submitbuttontoken.js:

 

require([
    'underscore',
    'jquery',
    'splunkjs/mvc',
    'splunkjs/mvc/simplexml/ready!'
], function (_, $, mvc) {
    // Initialize Default and Submitted Token Model.
    var defaultTokenModel = mvc.Components.get("default");
    var submittedTokenModel = mvc.Components.get("submitted");
    // #submit button Clicked
    $(document).on("click", "input#submitbutton", function (e) {
        // Default Token Model update For token value in UI
		defaultTokenModel.set("submitbutton", "*");
         // Submitted Token Model update For running searches on Dashboard with Submit Button.
		submittedTokenModel.set("submitbutton", "*");
    });
});

 

And here's a run anywhere example that uses that:

 

<dashboard script="submitbuttontoken.js">
  <init>
    <unset token="submitbutton"></unset>
  </init>
  <label>demodash</label>
  <fieldset submitButton="false" autoRun="false">
    <input type="dropdown" token="Input1">
      <label>Input1</label>
      <choice value="A">A</choice>
      <choice value="B">B</choice>
    </input>
    <input type="dropdown" token="Input2">
      <label>Input2</label>
      <choice value="C">C</choice>
      <choice value="D">D</choice>
    </input>
    <html>
      <input type="button" id="submitbutton" class="btn btn-primary" value="Submit"></input>
    </html>
  </fieldset>
  <search>
    <query>| makeresults count=1 
| search $submitbutton$
| eval search=if("A"=$Input1|s$ AND "C"=$Input2|s$,  "| makeresults | eval x=\"No\" | table x", "| makeresults | eval x=\"Yes\" | table x")
| table search</query>
    <done>
      <condition match="$job.doneProgress$=1">
        <set token="query">$result.search$</set>
      </condition>
    </done>
  </search>
  <row>
    <panel>
      <table>
        <search>
          <query>$query$ | search $submitbutton$</query>
        </search>
      </table>
    </panel>
  </row>
</dashboard>

 

 

If this comment/answer was helpful, please up vote it. Thank you.

View solution in original post

woodcock
Esteemed Legend

The simpleXML submit button is horribly broken and for complex usecases, cannot be made to work.  Try this dahsboard's no-JavaScript approach instead:

 

<form theme="dark">
  <label>PoC demonstrating a fully-functioning no-JS SUBMIT "button" (actually "checkbox").</label>
  <description>https://community.splunk.com/t5/Dashboards-Visualizations/SimpleXML-Inherent-brokenness-regarding-autorun-and-Submit/m-p/407351  For intricate technical reasons that Splunk considers "working as intended", the "real" SUBMIT button is fundamentally broken and CANNOT BE MADE TO WORK for many usecases (i.e. when you must use "true" for "searchWhenChanged").  Fortunately, the method demonstrated herein does everything that anyone could desire with only 1 downside which is this: there is no way to make the dashboard autorun on first load (not even if you click the CHECKBOX with a URI in the URL).  Notice that even though some of the controls interact with one-another, the actual search does not run until the SUBMIT box is checked.  Here are the pieces that are required. 1: DO NOT CHANGE ANYTHING ABOUT THE "SUBMIT" checkbox other than cosmetic things (e.g. html).  2: Ensure that EVERY OTHER CONTROL has a "&lt;change&gt;...&lt;/change&gt;" section that unsets BOTH these tokens: {"SUBMIT_CHECKBOX", "form.SUBMIT_CHECKBOX"}.  3: Ensure that 1 search in every chain of searches uses the do-nothing "$SUBMIT_CHECKBOX$" token somewhere (i.e. if all searches are driven by a base search, this only has to be done in the base search, not the post-process searches).  This token will always be either unset or blank so it does not matter where you put it.  4: Neither the individual "searchWhenChanged" values of the controls NOR the global "Autorun dashboard" value makes any difference.  For support contact woodcock@splunxter.com.</description>
  <fieldset submitButton="false" autoRun="true">
    <input type="multiselect" token="INDEX" searchWhenChanged="true">
      <label>Select Index value(s)</label>
      <fieldForLabel>label</fieldForLabel>
      <fieldForValue>value</fieldForValue>
      <default>*</default>
      <search>
        <query>|tstats count dc(host) WHERE index=* AND $SOURCETYPE$ BY index
| rename index AS value
| eval label = value
| append [|makeresults | eval label = "All", value="*"]
| table label value</query>
        <earliest>$timepicker.earliest$</earliest>
        <latest>$timepicker.latest$</latest>
      </search>
      <delimiter> OR index=</delimiter>
      <valuePrefix>"</valuePrefix>
      <valueSuffix>"</valueSuffix>
      <prefix>(index=</prefix>
      <change>
        <eval token="form.INDEX">case(mvcount($form.INDEX$) == 2 AND mvindex($form.INDEX$, 0) == "*", mvindex($form.INDEX$, 1), mvfind($form.INDEX$, "^[*]") == mvcount($form.INDEX$) - 1, "*", true(), $form.INDEX$)</eval>
        <unset token="SUBMIT_CHECKBOX"></unset>
        <unset token="form.SUBMIT_CHECKBOX"></unset>
      </change>
      <suffix>)</suffix>
    </input>
    <input type="multiselect" token="SOURCETYPE" searchWhenChanged="true">
      <label>Select sourcetype value(s)</label>
      <fieldForLabel>label</fieldForLabel>
      <fieldForValue>value</fieldForValue>
      <default>*</default>
      <search>
        <query>|tstats count dc(host) WHERE $INDEX$ AND sourcetype=* BY sourcetype
| rename sourcetype AS value
| eval label = value
| append [|makeresults | eval label = "All", value="*"] 
| table label value</query>
        <earliest>$timepicker.earliest$</earliest>
        <latest>$timepicker.latest$</latest>
      </search>
      <delimiter> OR sourcetype=</delimiter>
      <valuePrefix>"</valuePrefix>
      <valueSuffix>"</valueSuffix>
      <prefix>(sourcetype=</prefix>
      <change>
        <eval token="form.SOURCETYPE">case(mvcount($form.SOURCETYPE$) == 2 AND mvindex($form.SOURCETYPE$, 0) == "*", mvindex($form.SOURCETYPE$, 1), mvfind($form.SOURCETYPE$, "^[*]") == mvcount($form.SOURCETYPE$) - 1, "*", true(), $form.SOURCETYPE$)</eval>
        <unset token="SUBMIT_CHECKBOX"></unset>
        <unset token="form.SUBMIT_CHECKBOX"></unset>
      </change>
      <suffix>)</suffix>
    </input>
    <input type="text" token="COUNT">
      <label>Name for "count" field</label>
      <default>count</default>
      <change>
        <unset token="SUBMIT_CHECKBOX"></unset>
        <unset token="form.SUBMIT_CHECKBOX"></unset>
      </change>
    </input>
    <input type="time" token="timepicker" searchWhenChanged="true">
      <label>Timepicker</label>
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
      <change>
        <unset token="SUBMIT_CHECKBOX"></unset>
        <unset token="form.SUBMIT_CHECKBOX"></unset>
      </change>
    </input>
    <input id="submit_checkbox" type="checkbox" token="SUBMIT_CHECKBOX">
      <label></label>
      <delimiter> </delimiter>
      <choice value="">SUBMIT</choice>
    </input>
    <html depends="$hide$">
      <style>
        #submit_checkbox{
          width:80px !important;
        }
        #submit_checkbox
div[data-component="splunk-core:/splunkjs/mvc/components/LinkList"]{
          width:80px !important;
        }
        #submit_checkbox  button{
          padding: 6px 15px !important;
          border-radius: 3px !important;
          font-weight: 500 !important;
          background-color: #5cc05c !important;
          border: transparent !important;
          color: #fff !important
        }
        #submit_checkbox  button:hover{
          background-color: #40a540 !important;
          border-color: transparent !important;
        }
    </style>
  </html>
  </fieldset>
  <row>
    <panel>
      <table>
        <title>Searches ONLY on checking the SUBMIT box (which resets itself)</title>
        <search>
          <query>|tstats count AS $COUNT|s$ dc(host) WHERE $INDEX$ AND $SOURCETYPE$ BY index sourcetype $SUBMIT_CHECKBOX$</query>
          <earliest>$timepicker.earliest$</earliest>
          <latest>$timepicker.latest$</latest>
        </search>
        <option name="refresh.display">progressbar</option>
      </table>
    </panel>
  </row>
</form>

 

0 Karma

dmarling
Builder

Hi @Ingo,

The simplest way to do this with javascript would be to create a button input that on click sets a token that is present in all of your other searches.  You can also do this with simplexml, but it will add the token to the url when they click submit and I'm guessing you don't want that.

The below javascript will set a token defined with a name of "submitbutton" and a value of "*".  This value will only be set when clicking html submit button created in the xml.  In order for this to work you need to add "| search $submitbutton$" anywhere after the first line of your search and it will then prevent the search from running until the button is pushed.

Javascript for submitbuttontoken.js:

 

require([
    'underscore',
    'jquery',
    'splunkjs/mvc',
    'splunkjs/mvc/simplexml/ready!'
], function (_, $, mvc) {
    // Initialize Default and Submitted Token Model.
    var defaultTokenModel = mvc.Components.get("default");
    var submittedTokenModel = mvc.Components.get("submitted");
    // #submit button Clicked
    $(document).on("click", "input#submitbutton", function (e) {
        // Default Token Model update For token value in UI
		defaultTokenModel.set("submitbutton", "*");
         // Submitted Token Model update For running searches on Dashboard with Submit Button.
		submittedTokenModel.set("submitbutton", "*");
    });
});

 

And here's a run anywhere example that uses that:

 

<dashboard script="submitbuttontoken.js">
  <init>
    <unset token="submitbutton"></unset>
  </init>
  <label>demodash</label>
  <fieldset submitButton="false" autoRun="false">
    <input type="dropdown" token="Input1">
      <label>Input1</label>
      <choice value="A">A</choice>
      <choice value="B">B</choice>
    </input>
    <input type="dropdown" token="Input2">
      <label>Input2</label>
      <choice value="C">C</choice>
      <choice value="D">D</choice>
    </input>
    <html>
      <input type="button" id="submitbutton" class="btn btn-primary" value="Submit"></input>
    </html>
  </fieldset>
  <search>
    <query>| makeresults count=1 
| search $submitbutton$
| eval search=if("A"=$Input1|s$ AND "C"=$Input2|s$,  "| makeresults | eval x=\"No\" | table x", "| makeresults | eval x=\"Yes\" | table x")
| table search</query>
    <done>
      <condition match="$job.doneProgress$=1">
        <set token="query">$result.search$</set>
      </condition>
    </done>
  </search>
  <row>
    <panel>
      <table>
        <search>
          <query>$query$ | search $submitbutton$</query>
        </search>
      </table>
    </panel>
  </row>
</dashboard>

 

 

If this comment/answer was helpful, please up vote it. Thank you.

View solution in original post

Ingo
Engager

Awesome! Worked perfectly!

Modified the code slightly by re-/unsetting the submitbutton so the fileds could be modified and submitted again:

 

  <row>
    <panel>
      <table>
        <search>
          <query>$query$ | search $submitbutton$</query>
          <done>
            <unset token="submitbutton"></unset>
          </done>
        </search>
      </table>
    </panel>
  </row>

 

0 Karma
Did you miss .conf21 Virtual?

Good news! The event's keynotes and many of its breakout sessions are now available online, and still totally FREE!