When “All” are NOT Welcome–Getting Rid of that Pesky “All” Option on Dashboard Interactive Filters

What’s the goal here? Hiding the “All” option in a dashboard’s Interactive Filter.

That Pesky “All” Option on the Interactive Filter Has Got to Go!

Disclaimer: If you use this solution you do so at your own risk. We’ve all heard the warnings about DOM manipulation and the DOM we muck with here is very convoluted — so enter and use at your own risk.

Monty Python and the Holy Grail – The Rabbit Scene

Background:
In a scoped application, I have multiple dashboards that use the same interactive filter. The reports in that dashboard show values from a custom table which is updated weekly with a scheduled script execution. The day the script runs is the date added to a second custom table that contains the report run date. This is used to populate an interactive filter that is on each of these dashboards.

That interactive filter automatically adds an “All” option as the first option.

I needed that All option to go away because it pulls multiples of the same referenced records due to how the custom records are created and this duplication creates inaccurate reporting.

My Research:

You would think that there would be a configuration in the interactive filter to turn off that “All” option – no such luck!

In my research, I also found that many people have been looking for a solution to turn that “All” option off for similar reasons and I haven’t found a custom coded solution that works.

So, I started looking at a way to use some tomfoolery to mess with the DOM elements to possibly hide the first option that way. This led to some interesting discoveries.

The first thing I found is that the options are not a normal <select…> html element.

I also found that when one clicks on the field containing the options, it actually appears that some ajax runs that dynamically creates the options.

Those options are created in a series of hierarchical HTML elements – not easily reached – or so I thought.

My Solution:

This solution incurs some bit of a compromise, but one that is worth the compromise to hide the “All” option.

  1. Yes, I was able to figure out a reasonable solution and offer it here for your review and use.
  2. My concept was to somehow intercept whatever is calling the ajax when a user clicks on the option field then do something to capture the returning option values and hide the first one – the “All” option.
  3. Instead, through a contributor on stackoverflow.com, I found a javascript function that waits for the DOM to change then allows me to enter an HTML ID to look for. If that ID is found, then I can do something. This was a major breakthrough. I like to give credit where credit is due, so I added the URL to the article in the comments of my code–see below.
  4. What are the details of the solution? There are 3 connecting pieces that make up the whole solution.
    1. A UI Page (sys_ui_page table). In this page’s Client script box is that javascript function I mentioned above. It simply waits for the DOM to change – which happens when a user clicks the drop down field of the interactive filter – and then it looks for a specific HTML element ID that I know (after much searching with Chrome dev tools) houses the returning HTML elements that comprise the interactive filter options. In that returned HTML, I assume that the first series of HTML elements contains the “All” option and do a simply javascript style call to hide it. I also to a quick check to ensure that somewhere in the multi-leveled HTML structure is the “All” string before I do the javascript hide.
    1. A Widget (sys_widgets table). This is needed so I can get the code contained in the UI page onto each dashboard. This widget is a basic widget – I started by looking at the out-of-the-box world clocks widget, researching how to create widgets for dashboards and I eventually figured out how to create a bare-bones widget capable of calling the needed UI page above.
    1. Adding the Widget to each dashboard. To get this code to interact with the interactive filter, the code must be on the dashboard. I found after some trial and error that the code in the UI Page called in by the widget will run and affect anything on the dashboard page – meaning javascript in the Client script box of the UI Page will interact with any bit of the DOM on the dashboard – pretty darn snazzy! Here’s where the compromise is incurred—putting a widget a dashboard isn’t very flexible–you can’t really insert it so it’s not visible to the end user. Because it’s visible to the end user, it might cause some end users heartburn—they may not like it. So, placement can be an issue. I went with an option to try and make it seem like part of the user interface.

The Code:

Here are screen shots and code snippets for you perusal:

The UI Page:

Filling out the form:

  1. Name: choose your name (this is used in the widget code)
  2. Category: General.
  3. Description: Whatever you need to understand what this page does.
  4. Direct: Unchecked.
  5. HTML: Leave blank.
  6. Client script: here’s the code snippet:
// source for waiting for the DOM to change
// then check if a particular element with a ID exists
//https://stackoverflow.com/questions/37374117/continuously-check-if-something-exists-and-do-something

/*
So this is what's happening here:
1. The function below with the window.addEventListener waits for the DOM to change
2. In the Interactive Filter widget, when we click on the option box some ajax runs to grab the applicable 
options based on the interactive filter's configuration
   a. Then a dynamic set of options is created - each having the class 'select2-results-dept-0'
   b. The very first option is the one that is created with the value of "All"
   c. These are all enclosed in an HTML element with the id = "select2-drop"
*/
(function(doc,found) {
	window.addEventListener('DOMSubtreeModified', function() {
		var yourdiv = doc.querySelector("#select2-drop");
		if(found && !yourdiv){
			// Was there but is gone, do something
			found = false;
		}

		if(yourdiv){
			// Found it, do something
			found = true;
			/*
			remove the first element with a class of 'select2-results-dept-0'
			but be sure its innerHTML contains 'All'
			*/
			var interactiveFilterOptions = document.getElementsByClassName('select2-results-dept-0');
			var firstOption = interactiveFilterOptions[0];
			if (typeof firstOption !== "undefined"){
				var firstOptionHTML = firstOption.innerHTML;
				//console.log("firstOptionHTML: " + firstOptionHTML);
				if (firstOptionHTML.indexOf('All') > -1) {
					firstOption.style.display="none";
					// strange, but when the interactive filter dropdown is clicked, the console.log 
					// shows many "All" options - but I can live with that
					// as long as the darn All option doesn't appear to end users!
					//console.log("We're hiding the 'All' Option now.");
				}
			}
		}

	}, false);
})(document,false);

The Widget:

Filling out the form:

  1. Name: Give it a useful name.
  2. Renderer Type: JavaScript.
  3. Active: true.
  4. Roles: I don’t use – use as needed.
  5. Script: Things to Remember about the ‘name’ section of code:
    1. For scoped apps, prepend the name value with the scope “x_….”
    2. Otherwise just add a name of your chosing for the code part for ‘name’ : ‘namegoeshere’
    3. Code Snippet.
// ensure to prepend the 'name' below with the scoped app's scope "x...."
function sections() {
	return {
		'SELECT REPORT RUN DATE ABOVE TO UPDATE REPORTS:' : { 'name' : 'x_add_your_scope_here_this_part_must_match_the_name_field_of_the_ui_page' }
	};
}

function render() {
	var name = renderer.getPreference('name');
	return renderer.getRenderedPage(name);
}

function getEditLink() {
	if (!gs.hasRole('admin'))
		return '';

	return "sys_ui_page.do?sysparm_query=name=" + renderer.getPreferences().get("name");
}

The Dashboard: You need to add the widget to the dashboard.

Adding the Widget to the Dashboard is a click, select, resize and drag process.

Here are 2 screenshots showing how the widget works on the dashboard.

Where I Chose to Put the Widget on the Dashboard
Here we can see – there is no “All” option

Feel free to use this as your need dictates. If you have any questions, please go to my LinkedIn profile and message me or use the contact me form on this blog.

Synch Active Directory Users’ Status with ServiceNow Users – With Efficiency and Pizzazz

I found something peculiar with the way our LDAP user import was set up (or at least I felt it was a bit peculiar). We have never synched our ServiceNow users’ statuses (active/locked out) with the associated status in active directory. This rarely came up until I was asked to create a unique notification report for HR that required the knowledge if a user was active or not. This is my saga to find a way to ensure the users’ statuses in ServiceNow matched their status in active directory.

The back story (Note this was all done in our dev environment using an update set first [just in case you imagined I was doing this the fast way – directly in production.]):

Continue reading…

Mapping Self-Service Variables to Incidents

So here’s a request we had today. The service desk manager needed a new option for a self-service variable when a user was submitting a request for a problem they were experiencing.

To go with this new option, the manager needed the incident that is created to have specific values set for specific incident fields when a user selects this new option from the variable.

For the variable, the “Type Specification” was: Continue reading…

ServiceNow List Field Type: Displaying Values in Email Notifications

Displaying List Field Type Values in Email Scripts

When trying to display values from a List field in an email script you can’t simply display the field name from the form.

Here’s my specific work example:

I created a List field type called “Sizes Needed” (u_sizes_needed) in a form used to submit a marketing request.

This List type field references a custom table that has a single custom field called size (see Figure 1).

Continue reading…

Service Portal Journey Day 1

Join me in my journey to create a Service Portal for the Payroll department within my company to manage requests. My goal is to chronicle this entire process so I can reference it later for future Service Portals and so you can also use it as a guide for developing your Service Portal.

With every new software application the beginning is diving directly into coding … so here we go.

Ummm, wait a minute Rick. You code first? How do you know what the heck to code?

Continue reading…

Multi-Select Dropdowns in ServiceNow Don’t Exist – Here’s an Alternative

One thing that I find challenging in creating ServiceNow forms is the absence of multi-select dropdowns. There have been many times a customer needed to have this ability and I have resorted to using a series of checkboxes (true/false field type) as my alternative. I don’t like it, but it serves the purpose. Slushbuckets are only available for catalog items and record producers so I don’t have those available.

What’s a developer to do then?

Continue reading…

Using GlideRecord to get One Record

One of the coolest capabilities of ServiceNow is using Javascript to access database records. This is done using the GlideRecord() object. If you’re like Rick, you spent time searching how to use GlideRecord and when you found a solution, you copied and pasted it into your client script and moved onto the next challenge.

I discovered today that the problem with this technique is the first solution I found was not the optimal solution. Fortunately I happened across a TechNow Video that enlightened me on the best way.

In this case, I am trying to get a single user record from the sys_user table. Once I get the record I then use the person’s user_name from the user object to search for a record in a custom table. So here’s the inefficient way I was doing it (not efficient way in orange highlight):

var person = new GlideRecord(‘sys_user’);

Continue reading…