Everyone,
Assume that I have the token of $ticket_id$ on Page 1. The input type for this token is Multiselect. The multiselect search string is ticket_id="value1" OR ticket_id="value2"...
. The multiselect is working fine and loading the correct data for all the panels on Page 1, but when I have to drill down to another page; value1 and value2 are not getting passed. Instead, the multiselect search string is passing i.e ticket_id="value1" OR ticket_id="value2"...
. I understand that the multiselect string is replacing the token $ticket_id$.
Now, the drilldown target also has multiselect inputs. Is there a way to pass more than one value to the drilldown target?
The code for passing the values is as attached below:
<drilldown target="_blank">
<lnk>
<![CDATA[ ticket_review?form.severity=$row.severity$&form.ticket_id=$ticket_id$&form.time.earliest=$time.earliest$&form.time.latest=$time.latest$ ]]>
</lnk>
</drilldown>
Let me know.
I've had the same problem. The target dashboard needs the token url-encoded like form.ticket_id=value1&form.ticked_id=value2
and so on. My solution was to re-build the url-encoded token value in js before doing the drilldown, see here for sample code (not tested):
require([
"splunkjs/mvc",
"splunkjs/mvc/utils",
"splunkjs/mvc/simplexml/ready!"
],
function(mvc, utils) {
var tokens = mvc.Components.get("default");
var sourceMultiselect = splunkjs.mvc.Components.getInstance("multiselect");
var clickEventGenerator = ... // where your click comes from, e.g. a button or your table
clickEventGenerator.on("click", function(e) {
e.preventDefault(); // Stop default drilldown behavior
// Create token string from time tokens and multivalue inputs
var tokenString = "";
tokenString = "?form.time_tok.earliest=" + tokens.get("time_tok.earliest") + "&form.time_tok.latest=" + tokens.get("time_tok.latest"); // Use your other own static tokens here, e.g. severity
tokenString += returnUrldValues(sourceMultiselect.val(), "form.targetMultiselectTokenName"); // Add dynamic (mutlivalue) tokens here
// Handle click event regularly
var url = "/en-GB/app/appName/targetDashboard" + tokenString;
utils.redirect(url, false, "_blank");
});
// Returns concatenation of all entries in multiVals with prefixed targetTokenName
function returnUrldValues (multiVals, targetTokenName) {
var string = "";
for (var i = 0; i < multiVals.length; i++) {
string += "&" + targetTokenName + "=" + multiVals[i];
}
return string;
}
});
Hope that gets you started.
As an alternative to the JavaScript route, you could instead use the report search to set a field, then reuse that field in drilldown link:
With a multiselect producing a search string like (sourcetype=foo OR sourcetype=bar)
:
<input type="multiselect" token="sourcetypes" depends="$dt.earliest$,$dt.latest$" searchWhenChanged="true">
<label>Source Type</label>
<choice value="*">Show All</choice>
<default>Show All</default>
<search>
<query>index=_internal | stats count by sourcetype</query>
<earliest>$dt.earliest$</earliest>
<latest>$dt.latest$</latest>
</search>
<fieldForLabel>sourcetype</fieldForLabel>
<fieldForValue>sourcetype</fieldForValue>
<prefix>(</prefix>
<suffix>)</suffix>
<valuePrefix>sourcetype=</valuePrefix>
<delimiter> OR </delimiter>
</input>
Then using the above in the report search as a part of the search as well as setting a field _querystring
changing (sourcetype=foo OR sourcetype=bar)
into form.sourcetypes=foo&form.sourcetypes=bar
.
index="_internal" | search $sourcetypes$ | eval _querystring=replace(replace(ltrim(rtrim("$sourcetypes$",")"),"("),"sourcetype=","form.sourcetypes=")," OR ","&") | stats count by sourcetype, _querystring
Worth pointing out that you have to make sure the field _querystring
is in the results and then use dashboard visualisation to hide it.
Then this can be used in the drilldown link (using |n
to make sure it doesn't get escaped):
<link>
<![CDATA[mutliselect-drilldown?form.dt.earliest=$earliest$&form.dt.latest=$latest$&$row._querystring|n$]]>
</link>
Working example:
<form>
<label>Multiselect Drilldown</label>
<fieldset submitButton="false">
<input type="time" token="dt" searchWhenChanged="true">
<label></label>
<default>
<earliest>@d</earliest>
<latest>now</latest>
</default>
</input>
<input type="multiselect" token="sourcetypes" depends="$dt.earliest$,$dt.latest$" searchWhenChanged="true">
<label>Source Type</label>
<choice value="*">Show All</choice>
<default>Show All</default>
<search>
<query>index=_internal | stats count by sourcetype</query>
<earliest>$dt.earliest$</earliest>
<latest>$dt.latest$</latest>
</search>
<fieldForLabel>sourcetype</fieldForLabel>
<fieldForValue>sourcetype</fieldForValue>
<prefix>(</prefix>
<suffix>)</suffix>
<valuePrefix>sourcetype=</valuePrefix>
<delimiter> OR </delimiter>
</input>
</fieldset>
<row>
<panel>
<title>Source Types</title>
<table>
<search>
<query>
<![CDATA[index="_internal" | search $sourcetypes$ | eval _querystring=replace(replace(ltrim(rtrim("$sourcetypes$",")"),"("),"sourcetype=","form.sourcetypes=")," OR ","&") | stats count by sourcetype, _querystring]]>
</query>
<earliest>$dt.earliest$</earliest>
<latest>$dt.latest$</latest>
</search>
<option name="count">10</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">row</option>
<option name="rowNumbers">false</option>
<option name="wrap">true</option>
<fields>["sourcetype","count"]</fields>
<drilldown>
<link>
<![CDATA[mutliselect-drilldown?form.dt.earliest=$earliest$&form.dt.latest=$latest$&$row._querystring|n$]]>
</link>
</drilldown>
</table>
</panel>
</row>
</form>
Check the working project out here: https://github.com/mcwarman/splunk-multiselect-drilldown/.
Thank you for the alternative mwarman. I will look into implementing this as well when I get the chance to.
I've had the same problem. The target dashboard needs the token url-encoded like form.ticket_id=value1&form.ticked_id=value2
and so on. My solution was to re-build the url-encoded token value in js before doing the drilldown, see here for sample code (not tested):
require([
"splunkjs/mvc",
"splunkjs/mvc/utils",
"splunkjs/mvc/simplexml/ready!"
],
function(mvc, utils) {
var tokens = mvc.Components.get("default");
var sourceMultiselect = splunkjs.mvc.Components.getInstance("multiselect");
var clickEventGenerator = ... // where your click comes from, e.g. a button or your table
clickEventGenerator.on("click", function(e) {
e.preventDefault(); // Stop default drilldown behavior
// Create token string from time tokens and multivalue inputs
var tokenString = "";
tokenString = "?form.time_tok.earliest=" + tokens.get("time_tok.earliest") + "&form.time_tok.latest=" + tokens.get("time_tok.latest"); // Use your other own static tokens here, e.g. severity
tokenString += returnUrldValues(sourceMultiselect.val(), "form.targetMultiselectTokenName"); // Add dynamic (mutlivalue) tokens here
// Handle click event regularly
var url = "/en-GB/app/appName/targetDashboard" + tokenString;
utils.redirect(url, false, "_blank");
});
// Returns concatenation of all entries in multiVals with prefixed targetTokenName
function returnUrldValues (multiVals, targetTokenName) {
var string = "";
for (var i = 0; i < multiVals.length; i++) {
string += "&" + targetTokenName + "=" + multiVals[i];
}
return string;
}
});
Hope that gets you started.
Jeffland,
I will be accepting this answer since it seems to be the only good solution to the many multiselect questions being asked on this forum.
I am not versed in .js so I don't know where I should be adding this code ? Should I add this to an existing .js file or should I modify the code ,save it and then place the file in the C:\Program Files\Splunk\share\splunk\search_mrsparkle\exposed\js\splunkjs\mvc directory ?
Let me know. Thank you.
If you don't yet use custom js on your dashboard, you edit your Simple XML from
<form>
<label>Title</label>
<fieldset ...
to
<form script="myCustomJsFile.js">
<label>Title</label>
<fieldset ...
and place myCustomJsFile.js in C:\Program Files\Splunk\etc\apps<yourApp>\appserver\static.
Ok so I did as you mentioned and the default drilldown is still working it isn't getting prevented. The old URL is still populating.
I have done the following changes. Are these correct ? I have marked the changes I did in bold.
require([
"splunkjs/mvc",
"splunkjs/mvc/utils",
"splunkjs/mvc/simplexml/ready!"
],
function(mvc, utils) {
var tokens = mvc.Components.get("default");
var sourceMultiselect = splunkjs.mvc.Components.getInstance("multiselect");
var clickEventGenerator = **table** // where your click comes from, e.g. a button or your table
clickEventGenerator.on("click", function(e) {
e.preventDefault(); // Stop default drilldown behavior
// Create token string from time tokens and multivalue inputs
var tokenString = "";
tokenString = "&form**.time.earliest**=" + tokens.get("**time.earliest**") + "&form.**time.latest**=" + tokens.get("**time.latest**"); // Use your other own static tokens here, e.g. severity
**tokenString = "?form.severity=" + tokens.get("row.severity");**
tokenString += returnUrldValues(sourceMultiselect.val(), "form.**ticket_id**"); // Add dynamic (mutlivalue) tokens here
// Handle click event regularly
var url = "**http://localhost:8001**/en-US/app/**ticket_analysis/ticket_review**" + tokenString;
utils.redirect(url, false, "_blank");
});
// Returns concatenation of all entries in multiVals with prefixed targetTokenName
function returnUrldValues (multiVals, targetTokenName) {
var string = "";
for (var i = 0; i < multiVals.length; i++) {
string += "&" + **ticket_id**+ "=" + multiVals[i];
}
return string;
}
});
-- Also is for(var .. correct ?
What is table
in the line you're assigning it to the variable clickEventGenerator? It should be something like mvc.Components.get("tableId")
, where tableId is the id you've given your table in Simple XML. Also, you're overwriting tokenString in the fourth and fifth line of the on click function.
What is wrong with for (var ...
?
Jeffland,
I was busy in some work so I wasn't able to implement the code until today.
So I modified the code as you mentioned and the URL is still not updating with what I would like it to be. It is showing the default URL. I am trying to modify this for an app which has already been built. So is the URL hard coded ? I am just guessing.
Like I mentioned earlier I don't have much knowledge about coding in js. So I felt
for(var .. was incorrect since a few examples of .js I saw had only for( ..
Do you have any suggestions regarding this ? Thank you.
for (var i...
declares the variable i
in the scope of the current function, using for (i...
would make it global - general rule being to use the smallest necessary scope.
Are there any errors on your console? Also, I suspect the main question remains: what do you assign to the variable table
?
var clickEventGenerator = mvc.Components.get("severity_table");
The above is the modification I did to the code. severity_table is a table on the first page through which the value for severity is found.
Eg. If I click on the first row of severity_table I should get the corresponding value of severity from the first row , click on second row I should get the corresponding value of severity from the second row.. and so on.
Any click on the severity_table should start the drilldown to the next page along with the corresponding values for severity and other values like the multiselect inputs. The multiselect inputs are coming from a different panel than the severity table. And in the next page the values of the first page are passed and populated to new panels.
And you gave your table that id in Simple XML like this?
<row>
<panel>
<table id="severity_table">
<search...
Because then I don't see any reason it shouldn't basically work. Now with your explanation I doubt you can use "row.severity" to get the row of your click just like you could if you were doing this in Simple XML. Try the following:
clickEventGenerator.on("click", function(e) {
e.preventDefault();
console.log(e);
});
This should only stop the regular drilldown, and leave the e
element on your console. You can check it to see that it has a data
attribute which has your click event values. Try that and see if there are errors on your console. When that all works, you should be able to use
...
tokenString = "?form.severity=" + e.data["click.value"];
...
to get the leftmost cell value for the clicked row.
1) Yes the id in Simple XML is severity_table.
2) I opened the Console window on the first page in Chrome and the following is error is what I receive.
http://localhost:8001/en-US/splunkd/__raw/servicesNS/admin/MyAppName/static/appLogo.png
Failed to load resource: the server responded with a status of 404 (Not Found)
3)You mentioned that I would now be able to get the left most cell value.. But the left most cell doesnt have the value which I need. I might need to change the order of the table to get this working.
Mainly if modifying the URL works I could then focus on 3) and try to get that working as well. Thanks for following up jeffland.
That error has nothing to do with the problem, unfortunately.
If it's not the leftmost cell, then you should still be able to get the required row from the e
object. It has all rows from your table, you access them via e.data["row.severity"]
assuming your row is named severity (case sensitive of course).
You should set a breakpoint on the e.preventDefault();
row and have a look at the object.
jeffland,
Apologize for the delay in response. I got sometime to implement this today. I was able to have a look at the "e" object. The error I am facing in the console is as follows :
Uncaught TypeError: Cannot read property 'val' of undefined
at constructor.eval (eval at globalEval (common.js:1), <anonymous>:21:59)
at triggerEvents (common.js:205)
at constructor.trigger (common.js:205)
at triggerEvents (common.js:205)
at child.trigger (common.js:205)
at triggerEvents (common.js:205)
at child.trigger (common.js:205)
at eventsApi (common.js:205)
at child.trigger (common.js:205)
at child._emitDrilldownEvent (common.js:317)
The console is also highlighting this line of code :
tokenString += returnUrldValues(sourceMultiselect.val(), "form.targetMultiselectTokenName");
It would be helpful if I received a response. Thank you.
It looks like your code doesn't properly get your multiselect. Did you give it an id in Simple XML? If you didn't change it, it should be "multiselect" as per the line
var sourceMultiselect = splunkjs.mvc.Components.getInstance("multiselect");
Your Simple XML should declare the id like this:
...
<input id="multiselect" type="multiselect" token=...
That was it.. The input id wasn't set at all.. Thanks a lot jeffland, appreciate your effort as well as the followup.
There still seems to be one issue though.. The default drilldown is not getting prevented.. i.e there are two pages now.. one with the multiselect search string(default) and another one which is showing up due to the js code you provided.
That should not be the case if you're using e.preventDefault();
in the function which you call on('click'
of the table, i.e.
clickEventGenerator.on("click", function(e) {
e.preventDefault(); // Stop default drilldown behavior
This finally resolved Jeffland. Thank you.
I was using the following for drilling down to another page using Simple XML :
<lnk>
<![CDATA[ ticket_review?form.severity=$row.severity$&form.ticket_id=$ticket_id$&form.time.earliest=$time.earliest$&form.time.latest=$time.latest$ ]]>
</lnk>
</drilldown>
So the above needed to be removed from the Simple XML and then the .js code started working. I think preventDefault means : Stop the drilldown to the search page; because clicking on the table without having the .js code would go to the search page. Adding the .js code would stop this.
Another answer from you helped in resolving this.
https://answers.splunk.com/answers/492942/table-drilldown-disable-link-conditionally.html