banner



How To Use Interactive Filters In Servicenow Dashboards

Table of Contents

  • The limitations of standard filters
  • Creating a filter
  • How does the filter piece of work?
  • Updating the filter to lucifer Orlando functionality

The limitations of standard filters

In my previous post, I showed y'all how y'all can leverage a database view to report on multiple task types in the same widget. For the Performance Analytics Widgets, nosotros tin can utilize the dashboard breakdown to filter the widgets. That might not work for regular reporting widgets though, reporting widgets tin only exist filtered using interactive filters. However, the interactive filters we get out of the box can only filter on the post-obit field types:

  • choices fields (which reference the sys_choice table)
  • reference fields
  • engagement fields
  • boolean fields.

The "sys_class_name" (Task Type) field on task, and in our database view, is a special type of field. It only contains the proper name of the organization table the tape belongs to. By joining the sys_db_object tabular array to our database view, nosotros can besides include the sys_id of the tabular array. Yet, a sys_id field still isn't a field type that is supported by interactive filters (reference, boolean, choice, date).

We could work around this by adding a field to the chore table. The field would be a reference field to the sys_db_object record and be populated by a business rule running on insert. That would result in a reference field for the chore type that tin can be filtered by a standard interactive filter.

But if you don't want to modify the task table, at that place is another style. We can build a custom interactive filter using content blocks and jelly.

Creating a filter

We will be basing our filter on an example by Arnoud Kooi.

We start by adding a dynamic content cake to our dashboard by navigating to the "Content Cake" category and selecting "*New Dynamic Content":

Click the "Click Here" link in the added widget:

This takes united states to the input form for the dynamic content cake where we can start past giving information technology a name.

We then paste the post-obit code into the script field. Notice that at line 5 nosotros are limiting the options available to the ones nosotros desire to be able to filter for.

<?xml version="one.0" encoding="utf-eight" ?> <j:jelly trim="false" xmlns:j="jelly:core" xmlns:k="glide" xmlns:j2="null" xmlns:g2="null"> <!-- By Arnoud Kooi Check https://youtu.exist/I2eDVi9CAWI --> <thou:evaluate var="jvar_tasktypes" object="true" jelly="truthful"> var tables = 'incident,problem,change_request,sc_req_item,sc_task';  var obj=[]; var gr= new GlideRecord('sys_db_object');   gr.addEncodedQuery('super_classISNOTEMPTY^ORname=task^nameIN' + tables);   gr.addOrderBy('proper noun');   gr.query();   while(gr.next()){     obj.button([gr.getValue('name'),gr.getValue('label')]);   }   obj; </m:evaluate>       <select id='filter_task_type' class='select2-search' onchange='filterTaskType()'>         <option value="">All</option>         <j:forEach var="jvar_tasktype" items="${jvar_tasktypes}">              <selection value="${jvar_tasktype[0]}">${jvar_tasktype[1]}</option>                 </j:forEach>     </select>          <script>      var dbh = new DashboardMessageHandler("filter_tasktype");      function filterTaskType(){         var taskType = $j('#filter_task_type').val();         if (taskType)             dbh.publishFilter('u_task_extended','task_sys_class_name=' + taskType);         else             dbh.removeFilter();      }      filterTaskType(); </script>   </j:jelly>

Click submit. This adds the filter to the dashboard. It looks similar this:

We can and so add a listing report to our dashboard and set it to follow our filter by clicking the gear icon in the widget header and marking "Follow Interactive Filter". This will allow united states of america filter the list using the filter widget:

As you tin can see, the filter applies and updates the listing report.

Unfortunately, the drop downward listing is not recorded, but you get the point

How does the filter piece of work?

Now we have a working filter. Simply information technology would be good if you actually empathize how the script, and filter, works. Let's become over each part:

<?xml version="1.0" encoding="utf-8" ?> <j:jelly trim="false" xmlns:j="jelly:core" xmlns:thousand="glide" xmlns:j2="null" xmlns:g2="null">

The offset lines defines the xml version and encoding, and and then sets the namespaces for the jelly and glide files so they can be used in the script. Jelly is a scripting language that lets us generate HTML from XML.

<g:evaluate var="jvar_tasktypes" object="truthful" jelly="true">

This line tells us we are starting an expression that will be evaluated on the server. The script returns a variable chosen "jvar_tasktypes". The variable is an object and because "jelly" is set to true, the variable is bachelor for use in a client side script subsequently in the code.

var tables = 'incident,trouble,change_request,sc_req_item,sc_task';  var obj=[];

Two variables are then created, "tables" containing a string of comma-seperated table names and an empty array named "obj".

var gr= new GlideRecord('sys_db_object');   gr.addEncodedQuery('super_classISNOTEMPTY^ORname=task^nameIN' + tables);   gr.addOrderBy('name');   gr.query();   while(gr.next()){     obj.push([gr.getValue('name'),gr.getValue('label')]);   } obj;

GlideRecord is an object that will query the sys_db_object table to return properties of records in it.

An encoded query is then added to the GlideRecord. The query specifies that "Extends tabel" (super_class) is not empty, meaning that we will only go names of those tables that extend other tables. There is then a condition to likewise include the task table (which does not extend a table).
The last part of the query adds the status to only return records where the name field matches i of the tables specified in the "table" variable. The kickoff two parts of the query could actually exist removed, we only need the part that limits the results to those included in our tables-variable.
The results from sys_db_object will be sorted by their names thanks to gr.addOrderBy('name');.

The query is then executed by calling the .query() function.
A loop is initialized by the while-statement. This loop will execute while there are results in the GlideRecord. This means that for each records found by the query, something volition happen.

That something is that the "name" and "label" of each tape volition be added into an assortment, and that array will be added into the previously empty array chosen "obj". So obj volition be an assortment containing multiple other arrays:

ob[
[change_request,Change Request],
[incident,Incident],
[sc_req_item,Requested Item]
]

The final line returns the "obj" array for use in the script.
          <select id='filter_task_type' class='select2-search' onchange='filterTaskType()'>         <selection value="">All</option>         <j:forEach var="jvar_tasktype" items="${jvar_tasktypes}">              <option value="${jvar_tasktype[0]}">${jvar_tasktype[1]}</option>                 </j:forEach>     </select>        

In this part of the script, a drop-down box is added using HTMLs <select> tag. It has a course (select2-search) for CSS styling. When a choice is made, a function called filterTaskType() will be executed.

A forEach-loop using jelly is then started (j:forEach). Information technology iterates through each of the items in the variable jvar_tasktypes. Retrieve, this variable was ready at the offset of the script to contain names and labels for task types from the sys_db_object table. For every item in the array, an option is added to the drib down. The label from the assortment is set as the display value while the name from the array becomes the bodily selected value.

          <script>      var dbh = new DashboardMessageHandler("filter_tasktype");      part filterTaskType(){         var taskType = $j('#filter_task_type').val();         if (taskType)             dbh.publishFilter('u_task_extended','task_sys_class_name=' + taskType);         else             dbh.removeFilter();      }      filterTaskType(); </script>

This role of the script is the javascript that is run customer side, meaning in the user's browser.

On the second line, nosotros tin can see that a object is created from the DashboardMessageHandler class. Information technology is given a unique ID (filter_tasktype) and assigned to a variable called "dbh".
DashhoardMessageHandler is a ServiceNow class that can publish filters to other reporting widgets on the dashboard. You tin view the entire class and all of it'south methods past accessing:
http://your-servicenow-instance/scripts/classes/DashboardMessageHandler.js

After the DashboardMessageHandler object is created, the function referenced previously is defined; filterTaskType(). This function will run each fourth dimension the selection in the drib down box is changed. The function creates a variable chosen taskType and assigns it the value selected in the driblet down. If there is a value, the publishFilter() method of the DashboardMessageHandler class is called. This course takes a tabular array name as the first input (in this case set to the name of our database view, u_task_extended) and a encoded query string equally the 2d parameter. The encoded query is made up of a static string combined with the value of the "taskType" variable, meaning the value selected in the drop down.

If the value selected in the drop downward is empty, which information technology will be when selecting "All", as no value was specified for this choice in the earlier part of the script, the method removeFilter() of the DashboardMessageHandler object will exist called.

The methods of DashboardMessageHandler both fire events when called. These events are sent to all reporting widgets on the dashboard tab, and if the widget is set to follow interactive filters, it listens for these events. If the report in the widget is based on the same table as the first parameter of the publishFilter() method, the widget will apply this filter.

Updating the filter to match Orlando functionality

At present, when I first tried the filter I thought it worked fine, as you can come across in the short video beneath. But and then I noticed that if I left the dashboard and navigated back to information technology, or reloaded the page, or opened the dashboard in a new browser tab – the filter stopped working. It seemed similar it only worked in the first rendering of the dashboard.

I and then noticed that this could be fixed by opening the dashboard context menu and selecting "Reset Filters". See the video below for a demonstration of filters working, then not working after a page refresh, then working once more after a filter reset. Notice too how the debug widget is always updating with the correct filter. Information technology's just the reporting widgets that wont utilize it.

Now this is a fiddling strange. The ServiceNow documentation specifically mentions that custom interactive filters are not retained between page loads. It as well claims that when a report is refresh using the refresh-icon, the filter is removed. Then a reload of the page should remove the saved filter, but that is apparently non the instance.

The doc page for Custom Interactive Filters was updated for the Orlando release to include the following information:

The code that publishes the filter must call the SNC.canvas.interactiveFilters.setDefaultValue() method. It must also call the dashboardMessageHandler.publishFilter() method to publish the filter.

https://docs.servicenow.com/bundle/orlando-now-intelligence/page/use/dashboards/concept/c_CustomPublishers.html

The example custom interactive filter on the doc site has likewise been updated to include a call to SNC.canvas.interactiveFilters.setDefaultValue(). So even though the docs claim that interactive filters are not saved, that is no longer truthful since the Orlando release.

If we update our interactive filter to call the SNC.canvas.interactiveFilters.setDefaultValue() method, which requires usa to put our filter into an object passing that object to the method, the bug is resolved. We need to call this method both when changing the filter to a new task type, likewise every bit when showing all types. Information technology is non clear to me exactly where this default value that needs to be cleared is saved, but setDefaultValuie() defined in:
http://your-example-url/scripts/utils/InteractiveFilterUtils.js

          setDefaultValue: function(val, isPersistEnabled) {             if (JSON.stringify(val.filters) !== JSON.stringify(this.emptyFilter))                 this.defaultValues[val.id] = val.filters;             else {                 delete this.defaultValues[val.id];                 if (val.filters.selectedFilters) {                     var filters = {};                     filters.selectedFilters = val.filters.selectedFilters;                     val.filters = filters;                     this.defaultValues[val.id] = filters;                 }             }             if (isPersistEnabled) {                 this.saveDefaultValue(SNC.canvas.layoutJson.canvasSysId, {                     id: val.id,                     name: "default_value",                     filter: val.filters                 }, SNC.dashboards.dashboard.dashboardSysId);             }         },

After nosotros've added the new call to setDefaultValue(), our script should wait similar this, and function correctly:

<?xml version="one.0" encoding="utf-viii" ?> <j:jelly trim="false" xmlns:j="jelly:core" xmlns:1000="glide" xmlns:j2="goose egg" xmlns:g2="null"> <!-- By Arnoud Kooi Check https://youtu.exist/I2eDVi9CAWI --> <g:evaluate var="jvar_tasktypes" object="true" jelly="true"> var tables = 'incident,problem,change_request,sc_req_item,sc_task';  var obj=[]; var gr= new GlideRecord('sys_db_object');   gr.addEncodedQuery('super_classISNOTEMPTY^ORname=task^nameIN' + tables);   gr.addOrderBy('name');   gr.query();   while(gr.next()){     obj.push button([gr.getValue('name'),gr.getValue('characterization')]);   }   obj; </g:evaluate>       <select id='filter_task_type' class='select2-search' onchange='filterTaskType()'>         <pick value="">All</option>         <j:forEach var="jvar_tasktype" items="${jvar_tasktypes}">              <choice value="${jvar_tasktype[0]}">${jvar_tasktype[1]}</option>                 </j:forEach>     </select>          <script>      var dbh = new DashboardMessageHandler("filter_tasktype");      function filterTaskType(){         var taskType = $j('#filter_task_type').val();          		 var filter_message = {}; 		 filter_message.id = "taskFilter" 		 filter_message.tabular array = "u_task_extended"           		if (taskType) { 			filter_message.filter = "task_sys_class_name="+taskType;	  			SNC.canvas.interactiveFilters.setDefaultValue({ 				id: filter_message.id,                 filters: [filter_message]             }, imitation); 		 dbh.publishFilter(filter_message.table, filter_message.filter); 		}         else { 		filter_message.filter = "";	  			SNC.canvass.interactiveFilters.setDefaultValue({ 				id: filter_message.id,                 filters: [filter_message]             }, fake); 			dbh.removeFilter(); 		}      }      filterTaskType(); </script>   </j:jelly>

How To Use Interactive Filters In Servicenow Dashboards,

Source: https://performinganalytics.com/an-example-of-advanced-custom-interactive-filters-for-dashboards/

Posted by: robinsonbitterephe56.blogspot.com

0 Response to "How To Use Interactive Filters In Servicenow Dashboards"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel