Dynamic Service Portal Breadcrumbs, Perfected

“Perfection is finally attained not when there is no longer anything to add but when there is no longer anything to take away, when a body has been stripped down to its nakedness.”
Antoine de Saint-Exupéry

Years ago, I was taught that there was three kinds of software maintenance, Corrective, Adaptive, and Perfective. There are those that will tell you that there is a fourth kind, called Preventive or Preventative depending on where and when you learned the English language, but in my mind, that doesn’t really apply to software. Preventative maintenance is done to physical assets like a vehicle or an elevator or a machine on the factory floor. The idea behind preventative maintenance is to lubricate or replace parts before they wear out to prevent a breakdown. Preventative maintenance is usually performed on a schedule based on the anticipated lifespan of the parts in question. Having your car serviced by the dealer periodically in accordance with the schedule laid out in the owner’s manual is a form of preventative maintenance. Software, though, is not constructed out of physical parts that wear out, so I can’t imagine what task that you could perform on a piece of software that you could consider preventive. But, I digress …

Today, we’re going to talk about some Perfective Maintenance done on my old friend, the Dynamic Service Portal Breadcrumbs widget. I didn’t want to change its function or features — that wouldn’t be maintenance at all; that would be an Enhancement — and I wasn’t trying to fix anything (Corrective) and I wasn’t trying to conform to a new browser or a new version of ServiceNow (Adaptive). I just wanted to make it better, which is the essence of Perfective Maintenance.

But how could it possibly be any better, you ask? While that is definitely a reasonable question, there is always room for improvement on just about everything. One thing that has always annoyed me was the presence of the portal title in breadcrumbs when just the page title would do. You can see an example of that on this image from an earlier installment on this component:

Breadcrumbs with Page Title/Portal Title as Label

I never liked that. It was redundant, and it made individual elements of the breadcrumbs much wider than they needed to be. So I added this code to search for that and remove it:

var thisTitle = c.data.page || document.title;
var portalSuffix = ' - ' + $rootScope.portal.title.trim();
var cutoff = thisTitle.indexOf(portalSuffix);
if (cutoff != -1) {
	thisTitle = thisTitle.substring(0, cutoff);
}
var thisPage = {url: $location.url(), id: $location.search()['id'], label: thisTitle};

That should work for as long as ServiceNow tacks the portal title on to the end of the page title using a dash surrounded by single spaces as a separator. If that convention ever changes, then this will need to be revisited and adjusted accordingly.

One other thing that always disturbed me was that the breadcrumb trail lasted forever, and if you were off of the site for a few days and then came back, your breadcrumbs from your last session would still be active. It seemed to me that, once you have been gone for some time, your breadcrumbs should start fresh back at the home page again. To make that happen, I added one more User Preference for the session ID, and only used the breadcrumb trail if it came from the same session. That code lives on the server side, and looks like this:

data.breadcrumbs = [];
var snhbc = gs.getPreference('snhbc');
var snhses = gs.getPreference('snhses');
if (snhbc && snhses && snhses == thisSession) {
	data.breadcrumbs = JSON.parse(snhbc);
}

One other thing I did was to look at the generic display value for the current record before searching for specific fields. Many tables already have a display field selected as part of the table definition, so using the getDisplayValue() method without passing any arguments can save all of that hunting around for the right field to use. If there is no defined display field, though, it will return the creation date with a label of ‘Created’, which we don’t want, so we have to check for that as well. That new code now looks like this:

data.page = rec.getDisplayValue();
if (data.page.indexOf('Created') == 0) {
	data.page = null;
}
if (!data.page) {
	data.page = rec.getDisplayValue('number');
}
if (!data.page) {
	data.page = rec.getDisplayValue('name');
}
if (!data.page) {
	data.page = rec.getDisplayValue('short_description');
}
if (!data.page) {
	data.page = rec.getLabel();
}

So, just a few little tweaks here and there to spruce things up a bit. No features added, no features taken away, and no defects repaired. Just a little tidying up to make it even better than it was before. For those of you who like to play along at home, here is the most recent Update Set.

Update: There is an even better version, which you can find here.