Customizing the Data Table Widget

“The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man.”
George Bernard Shaw

After spending some time playing around with my Data Table Widget Content Selector, I realized that there were a few things that I wanted out of the Data Table widget that just weren’t on its list of features. For one thing, the entire row was the source of the link to further details. In the standard ServiceNow UI, the first column on any given list is the link to further details on the subject of the the row, and links in other columns took you to details related to that specific column. On a list of Incidents, for example, clicking on the link on the first column will take you to the Incident, but clicking on a link in any other column, say Assignment Group or Location, will bring up information on the Assignment Group or Location. I wanted to have a Service Portal list that behaved in the same manner. I started rooting around in the code for the Data Table and realized that this would be more than a simple hack, so I decided to clone the widget and create my own SNH Data Table.

One thing that I discovered while playing around with my copy of the Data Table widget was that there was a minor bug in widget related to the fields option, which was the subject of my earlier hack of the Data Table from URL definition widget. Throughout the widget, this option is referenced as fields, but in the actual widget options, it is named field_list. The statement that copied fields from the options didn’t really copy anything, as the actual data was stored under the variable name field_list. So the first thing that I ended up doing with my copy was to change this:

if (!data.fields) {
	if (data.view)
		data.fields = $sp.getListColumns(data.table, data.view);
	else
		data.fields = $sp.getListColumns(data.table);
}

… to this:

if (!data.fields) {
	if (data.field_list) {
		data.fields = data.field_list;
	} else if (data.view) {
		data.fields = $sp.getListColumns(data.table, data.view);
	} else {
		data.fields = $sp.getListColumns(data.table);
	}
}

That seemed to have rectified that little shortcoming, so now back to my intended purpose, which was to provide column-level links rather than the current row-level link. First things first: I needed to find out if we had enough information on hand to provide the links, or if we needed to add some code to gather up more details for columns that could contain a link. Unfortunately, the code the code that gathers up the row data doesn’t reveal much detail on what, exactly, is gathered up for each field in each row:

while (gr._next()) {
	var record = {};
	$sp.getRecordElements(record, gr, data.fields);
	. . .
}

I would have to dig out the code for $sp.getRecordElements() to know what data was being pulled for each field, which sounded a lot like a major hunting expedition. Instead, I took the lazy way out (my favorite!), and just dumped out the result with a gs.info(JSON.Stringify(record)); statement right after the $sp.getRecordElements(). After that, all I had to do was to bring up a list using the widget and then dig through syslog.list. What I learned was that each field in the record object contained a type, a value, and a display_value, but not the name of the table for the reference fields, which I would need if I was going to create a link. So, I needed to add a little code to pick up that extra bit of info for each field where type=reference. There was actually some similar code right above where I needed to insert my own, so what I ended up adding turned out to be a bastardized copy of the preceeding logic:

for (var f in data.fields_array) {
	var fld = data.fields_array[f];
	if (gr.isValidField(fld)) {
		if (record[fld].type == 'reference') {
			record[fld].table = gr.getElement(fld).getED().getReference();
		}
	}
}

Basically, we just loop through all of the fields in the record, look for those where type=reference and then go fetch the reference table from the source GlideRecord. Now that we have everything that we need in the underlying data, the last thing that we need to do will be to alter the HTML to provide individual column links instead of a single link for the entire row. That seems like a good place to start, next time out