Dashboards & Visualizations

Remove "All" from Multiselect Input in Dashboard

ashish9433
Communicator

Hi Team,

I have multiple "Multiselect" Input on my Dashboard which has search query which populates the result for Multiselect along with a static option of All (*)

Now, i want that whenever anyone selects any one or Multiple values in Multiselect input, "All" should automatically gets removed. Currently the user has to remove "All" and if user doesn't remove "All" then the result is skewed.

The results is getting skewed because we are using OR clause.

For example

When only ALL is selected (default) below search query runs

index=abc | search xzy=* | stats count by xyz

When other values are also selected along with ALL

index=abc | search xzy=* OR xzy=hello OR xzy=hi OR xzy=how | stats count by xyz

Now in the above case since "All" is by default selected, and even person selects other name the results show for all users as xzy=* remains and user has to explicitly remove ALL from the multiselect.

What i am looking for is whenever any user selects anything from the multiselect input, All should automatically be removed/de-selected.

Labels (2)
1 Solution

ashish9433
Communicator

I followed the advice by @jeffland in Link and using the below JS i was able to achieve what i was looking for.

require([
     'jquery',
     'splunkjs/mvc',
     'splunkjs/mvc/simplexml/ready!'
 ], function($, mvc){
         $('#multi').on("change",function(){
                 var multi1 = mvc.Components.get("multi");
                 var tokens = mvc.Components.getInstance("default");
                 var mytoken = tokens.get("multi")

                  if (mytoken.length > 1 && mytoken.includes("All"))
                 {
                     // If "All" was selected before current (more specific) selection, remove it from list
                     if (indexOfAll == 0) 
                     {
                         var temp = mytoken.split(" ")
                         var temp1 = temp[1]
                         multi1.val(temp1);
                     } else 
                     {
                         // "All" was selected last, clear input and leave only "All" in it
                         multi1.val("All");
                     }
                 }


 }); 
 }); 

View solution in original post

phoenix_down
Path Finder

I was not able to get either of the above answers to work for me in Splunk 6.6.1, so I wrote my own using plain Javascript without the need for jQuery. This is also a generic solution that works for any number of multi-selects on the page.

require([
    'splunkjs/mvc',
    'splunkjs/mvc/simplexml/ready!'
], function(mvc) {

    function setupMultiInput(instance_id) {

      // Get multiselect
      var multi = mvc.Components.get(instance_id);

      // On change, check selection
      multi.on("change", (selectedValues) => {

        if (selectedValues.length > 1 && selectedValues.includes("*")) {
          var indexOfAll = selectedValues.indexOf("*");

          // If "ALL" was selected before current (more specific) selection, remove it from list
          if (indexOfAll == 0) {
            selectedValues.splice(indexOfAll, 1);
            multi.val(selectedValues);
            multi.render();
          } else {
            // "ALL" was selected last, clear input and leave only "ALL" in it
            multi.val("*");
            multi.render();
          }
        }

      });
    }

    var all_multi_selects = document.getElementsByClassName("input-multiselect");
    for (j = 0; j < all_multi_selects.length; j++) {
      setupMultiInput(all_multi_selects[j].id);
    }

});

The assumption is that the default value is "*". But you can easily modify the code if you use something different for the default value.

Then all you have to do is to include the script at the top of your dashboard code:

<form script="path/to/multiselect.js">

premranjithj
Builder

@phoenix_down @niketnilay this works on all the multiselect present in the dashboard but i need to make it work on the single mutliselect.
could you please help?

0 Karma

phoenix_down
Path Finder

Is there any reason why you only want it to work on a single multiselect? Usually people want this to be the default behavior for all multiselects on the page.

In any case, you can replace this:

var all_multi_selects = document.getElementsByClassName("input-multiselect");
     for (j = 0; j < all_multi_selects.length; j++) {
       setupMultiInput(all_multi_selects[j].id);
     }

With:

 var this_one_multiselect = document.getElementById("my_multiselect_id");
 setupMultiInput(this_one_multiselect);

Where your multiselect has the id of "my_multiselect_id".

0 Karma

premranjithj
Builder

@phoenix_down i added id to panel and replaced the code but now its not resetting the "All" selection from mutiselect input.

if i keep all to all multiselect to reset its not working on the other panels to add new values. thats is why i need to keep restricting it to single multiselect

0 Karma

phoenix_down
Path Finder

Keep in mind that with the code snippet as shown, your "All" label must have a value of "*****", otherwise it will not work. Please check to make sure that is the case in your code.

0 Karma

premranjithj
Builder

@phoenix_down this is the modified code JS with ID name, which has value for "*" in the input but its not working

require([
'splunkjs/mvc',
'splunkjs/mvc/simplexml/ready!'
], function(mvc) {
function setupMultiInput(instance_id) {

       // Get multiselect
       var multi = mvc.Components.get(instance_id);

       // On change, check selection
       multi.on("change", (selectedValues) => {

         if (selectedValues.length > 1 && selectedValues.includes("*")) {
           var indexOfAll = selectedValues.indexOf("*");

           // If "ALL" was selected before current (more specific) selection, remove it from list
           if (indexOfAll == 0) {
             selectedValues.splice(indexOfAll, 1);
             multi.val(selectedValues);
             multi.render();
           } else {
             // "ALL" was selected last, clear input and leave only "ALL" in it
             multi.val("*");
             multi.render();
           }
         }

       });
     }

     var this_one_multiselect = document.getElementById("my_multiselect_id");
  setupMultiInput(this_one_multiselect);


 });

 <input type="multiselect" token="AURA" id="my_multiselect_id" searchWhenChanged="false">
        <label>Select value</label>
        <fieldForLabel>AURANAME</fieldForLabel>
        <fieldForValue>AURANAME</fieldForValue>
        <search>
          <query>| inputlookup  </query>
        </search>
                <choice value="*">All</choice>
        <valuePrefix>"</valuePrefix>
        <valueSuffix>"</valueSuffix>
        <delimiter>,</delimiter>
      </input>
0 Karma

phoenix_down
Path Finder

If you use inspect elements in your browser's developer tools (in Chrome, it's View ->Developer->Inspect Elements) and select your multi-select, it should look something like this:

<div id="my_multiselect_id" data-cid="view14086" class="input input-multiselect" data-view="views/dashboard/form/Input" data-render-time="0.01">

Are you seeing that, or something else? What version of Splunk are you using?

0 Karma

premranjithj
Builder

@phoenix_down I am getting below things in inspect for the multiselect. i am using 8.0.1 version

<div class="splunk-view splunk-multidropdown splunk-choice-input" id="my_multiselect_id_10342" data-view="splunkjs/mvc/multidropdownview">
0 Karma

phoenix_down
Path Finder

I see what the problem is now. The downside of custom JS code is that Splunk could change the structure of its elements under the hood and break your code, which is what happened here. Looks like Splunk 8.x changed some things under the hood. Not only is the "input-multiselect" class gone (which broke my original code that worked for any number of multi-selects), the id that you specified is now appended with a number (which breaks the new single multi-select code).

Try this code and see if it works:

 require([
     'splunkjs/mvc',
     'splunkjs/mvc/simplexml/ready!'
 ], function(mvc) {

     function setupMultiInput(instance_id) {

       // Get multiselect
       var multi = mvc.Components.get(instance_id);

       // On change, check selection
       multi.on("change", (selectedValues) => {

         if (selectedValues.length > 1 && selectedValues.includes("*")) {
           var indexOfAll = selectedValues.indexOf("*");

           // If "ALL" was selected before current (more specific) selection, remove it from list
           if (indexOfAll == 0) {
             selectedValues.splice(indexOfAll, 1);
             multi.val(selectedValues);
             multi.render();
           } else {
             // "ALL" was selected last, clear input and leave only "ALL" in it
             multi.val("*");
             multi.render();
           }
         }

       });
     }

     var all_multi_selects = document.getElementsByClassName("splunk-multidropdown");
     for (j = 0; j < all_multi_selects.length; j++) {
       setupMultiInput(all_multi_selects[j].id);
     }

 });

premranjithj
Builder

@phoenix_down its works on the multiselect to remove other values if i select "All" and vice versa.
i have option in multiselect 1 to unset token on multiselect2 if any value selection is reset on multiselect1 but now after token unset , i am not able to select /pick any values on multiselect2.

if i remove unset token tag its working fine, is any changes needed on JS to work?

 `
            <label>Select </label>
            <fieldForLabel>SiteName</fieldForLabel>

            <fieldForValue>SiteName</fieldForValue>

            <search>

              <query>| inputlookup </query>

            </search>
            <change>
              <condition>

              <unset token="form.Multiselct2"></unset></condition>

            </change>
            <choice value="*">All</choice>

            <valuePrefix>"</valuePrefix>

            <valueSuffix>"</valueSuffix>

            <delimiter>,</delimiter>

          </input>`
0 Karma

phoenix_down
Path Finder

Instead of unsetting Multiselect2, can you set it to a default value?

0 Karma

premranjithj
Builder

@phoenix_down in mutiselect2 ALL values is not a * value. collectively of selection on multiselect1 so we cant set default value.

multiselect2 :

<div data-test-values="[]" data-test="multiselect" data-component="splunk-core:/splunkjs/mvc/components/MultiDropdown" data-size="medium" data-test-popover-id="popover-fa6e2cf8-a4b2-4561-b0a1-876edb52852e" data-popoveropen="false" role="listbox" class="NormalStyles__StyledBox-sc-2uz0a2-0 jYRcTO BoxStyles__Styled-sc-1f3k58w-0 eLYusu" data-inline="true" data-flex="true" style="width: 200px;"><div role="combobox" aria-haspopup="true" aria-expanded="false" class="NormalStyles__StyledInputWrapper-sc-2uz0a2-1 kodZxK"><input data-test="textbox" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-autocomplete="list" placeholder="Select..." data-size="medium" class="NormalStyles__StyledInput-sc-2uz0a2-2 eKdXWT" value="" style="flex-basis: 0em; width: 0em;"></div></div>

multiselect2 textbox:

<input data-test="textbox" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-autocomplete="list" placeholder="Select..." data-size="medium" class="NormalStyles__StyledInput-sc-2uz0a2-2 eKdXWT" value="" style="flex-basis: 0em; width: 0em;" aria-activedescendant="active-item-6b2ed47c-f941-490b-8691-8cf1cdfe6c1c" aria-controls="popover-fa6e2cf8-a4b2-4561-b0a1-876edb52852e">
0 Karma

phoenix_down
Path Finder

I missed your reply somehow. Can you post your code for "Multiselect2"?

0 Karma

premranjithj
Builder

@phoenix_down
below are the multiselect2.

multiselect1:

<input type="multiselect" id="ALL_RESET" token="shops" searchWhenChanged="true">
        <label>Select shops</label>
        <fieldForLabel>SiteName</fieldForLabel>
        <fieldForValue>SiteName</fieldForValue>
        <search>
          <query>| inputlookup </query>
        </search>
        <choice value="*">---All shops---</choice>
        <valuePrefix>"</valuePrefix>
        <valueSuffix>"</valueSuffix>
        <delimiter>,</delimiter>
<change>
<unset>form.multiselec2</unset>
</change>
      </input>

multiselect2:
 <input type="multiselect" token="Name" id="multiselectId" searchWhenChanged="false">
            <label>Select Server(s)</label>
            <search>
              | inputlookup lookupsheet.csv| search Name IN ($Name$) | dedup Servers | table Servers | sort Servers | append[| inputlookup lookupsheet.csv| | search Name IN ($NAME$) | dedup Servers | table Servers | eval host="\"".Servers."\"" | stats delim="," values(host) AS host | mvcombine host] | eval host=if(host!="*",host,Servers) | fillnull value="ALL Servers" | sort Servers

     <fieldForLabel>Servers</fieldForLabel>
             <fieldForValue>host</fieldForValue>
             <delimiter>,</delimiter>
                  </input>

multiselect 2 has dynamic value "All shops" which is generated from search.
so its not picking the check
ex: if selection is 2 shops, the SPl result will be
1.shop1
2, shp2
3.All shops(shop1,shop2)
its not working if results where dynamic coming from the search

Javascript for multiselect2"

 require([
      'underscore',
      'splunkjs/mvc',
      'splunkjs/mvc/simplexml/ready!'], function (_, mvc) {

  var multiselect = splunkjs.mvc.Components.getInstance("multiselectId");
  multiselect.on("change", function (value) {
      var defaulLabel="All Shops";
      if (value.length > 1 && ~(value.indexOf(defaulLabel))) {
          if (value.indexOf(defaulLabel) == 0) {
              value.splice(value.indexOf(defaulLabel), 1);
              this.val(value);
              console.log("Final ",value);
          } else {
              this.val(defaulLabel);
          }
          this.render();
      }
  })
  });
0 Karma

dhirendra761
Contributor

yes it worked for me also...... Thanks for your code....@phoenix_down

0 Karma

tonyca
Explorer

Thanks @phoenix-down .it is working for all multi select inputs.

0 Karma

niketnilay
Legend

@tonyca, do up-vote this answer if it has helped 🙂

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"

ashleyherbert
Communicator

Just thought I'd post an alternative way of doing this. I'm not a big fan of adding javascript to my dashboards, so I've found a way to do this by adjusting the token for the input using the change & eval attributes. See the example below from one of our dashboards:

    <input type="multiselect" token="host" searchWhenChanged="true">
      <label>Hosts</label>
      <search base="lookup">
        <query>search $env$ | dedup host</query>
      </search>
      <valuePrefix>host=</valuePrefix>
      <delimiter> OR </delimiter>
      <default>*</default>
      <choice value="*">All</choice>
      <fieldForLabel>host</fieldForLabel>
      <fieldForValue>host</fieldForValue>
      <change>
        <eval token="form.host">if(mvcount('form.host')=0,"*",if(mvcount('form.host')!=1,mvfilter('form.host'!="*"),'form.host'))</eval>
      </change>
    </input>

This will reset the token to 'All' if no options are selected, and will remove the 'All' option if more than 1 are selected.

UPDATE:
One of my colleagues found this didn't work properly. When you select a couple of hosts, the only way to get back to 'All' is to remove all your previous selections, at which point 'All' will re-appear. Below is the fix he added, this is the commentary from our internal Jira system:

Basically, because of the '*', the regex doesn't quite work, so we need to change the

<choice value="*">All</choice>

to

<choice value="All">All</choice>

so the regex mvfind works as expected. Then, set a second token dependent on the value of 'form.blah', which is then used in any post-process search [decided to change the name of the original multi-select form token, and then set a token with the old name, so it remains transparent to the post-process searches that use the original token].

So:
- it defaults to 'All' (All is alone at the start, index=0)
- if another env is chosen, 'All' is removed
- if 'All' is chosen, all other envs are removed (ie All is always alone at the start, index=0)
- if everything is removed, 'All' reappears (ie All is always alone at the start, index=0)

<input type="multiselect" token="env2" searchWhenChanged="true">
  <label>Environment</label>
  <search base="lookup">
    <query>dedup environment</query>
  </search>
  <default>All</default>
  <valuePrefix>environment=</valuePrefix>
  <delimiter> OR </delimiter>
  <choice value="All">All</choice>
  <fieldForLabel>environment</fieldForLabel>
  <fieldForValue>environment</fieldForValue>
  <change>
    <eval token="form.env2">case(mvcount('form.env2')=0,"All",mvcount('form.env2')&gt;1 AND mvfind('form.env2',"All")&gt;0,"All",mvcount('form.env2')&gt;1 AND mvfind('form.env2',"All")=0,mvfilter('form.env2'!="All"),1==1,'form.env2')</eval>
    <eval token="env">if(mvfind('form.env2',"All")=0,"environment=*",$env2$)</eval>
  </change>
</input>

...still use $env$ where appropriate

<input type="dropdown" token="host" searchWhenChanged="true">
<label>Select a Host:</label>
<selectFirstChoice>true</selectFirstChoice>
<search base="lookup">
<query>search $env$ | dedup host</query>
</search>

Hope this helps, cheers.

yshen
Path Finder

@ashleyherbert  following your elegant idea using change clause, I implemented mine below:

 

 

 

<form>
  <label>Adaptive Option All</label>
  <fieldset submitButton="false">
    <input type="multiselect" token="dev_type" searchWhenChanged="true">
      <label>Type of Sensor</label>
      <choice value="*">All</choice>
      <default>*</default>
      <prefix>(</prefix>
      <suffix>)</suffix>
      <initialValue>*</initialValue>
      <delimiter>, </delimiter>
      <fieldForLabel>Device_Type</fieldForLabel>
      <fieldForValue>Device_Type</fieldForValue>
      <search>
        <query>index="cse_scada"
        | dedup Device_Type
        | sort Device_Type&lt;</query>
        <earliest>0</earliest>
        <latest></latest>
      </search>
      <change>
        <eval token="form.dev_type">
          case(
          mvcount('form.dev_type')=0,"*", <!-- when there is non selected, set to "*" -->
          mvcount('form.dev_type')&gt;1 AND mvfind('form.dev_type',"*")&gt;0,"*", <!-- when there are more than one selected, and "*" is not the first one, set to "*" -->
          mvcount('form.dev_type')&gt;1 AND mvfind('form.dev_type',"*")=0,mvfilter('form.dev_type'!="*"), <!-- when there are more than one selected, and "*" is the first one, remove "*" -->
          1==1,'form.dev_type' <!-- otherwise no change -->
          )
        </eval>
      </change>
    </input>
  </fieldset>
</form>

 

 

 

but it does not work. 

When I selected a specific option "*" (All) does not disappear. 

After having specific option(s), selecting "*" (All), the other option(s) do not disappear.

Would you please help to diagnose what could go wrong?

Thanks!

-- 

I suspect that it might be related how the list of values for the token dev_type is represented, as I observed, when only "*" is selected, the corresponding URL is 

 

http://l-yshen:8000/en-US/app/search/trychangeadaptiveall?form.dev_type=*

 

when one more option is selected, say "UPS", the corresponding URL becomes

 

http://l-yshen:8000/en-US/app/search/trychangeadaptiveall?form.dev_type=*&form.dev_type=UPS

It seems the manipulation in the change clause takes no effect.

 

0 Karma

karan2627
New Member

Thanks @ashleyherbert for this. it worked for me but the problem is with this the submit button has stopped working means with this code i have to mark "search on change = true", with search on change = false the above code doesn't work.

So is there any way to to make this code work without "search on change = true". It would be great help.. below is the code

  <label>Connection Id (Only for PF App)</label>
  <choice value="All">All</choice>
  <change>
    <condition>
      <eval token="connection">case(mvcount('connection')=0,"All",mvcount('connection')&gt;1 AND mvfind('connection',"All")&gt;0,"All",mvcount('connection')&gt;1 AND mvfind('connection',"All")=0,mvfilter('connection'!="All"),1==1,'connection')</eval>
      <eval token="connection">if(mvfind('connection',"All")=0,"connectionid=*",connectionid $connection$)</eval>
    </condition>
  </change>
  <fieldForLabel>connectionid</fieldForLabel>
  <fieldForValue>connectionid</fieldForValue>
0 Karma
Take the 2021 Splunk Career Survey

Help us learn about how Splunk has
impacted your career by taking the 2021 Splunk Career Survey.

Earn $50 in Amazon cash!