Configurable Data Table Widget Content Selector, Part III

“Everyone thinks of changing the world, but no one thinks of changing himself.”
— Leo Tolstoy

After all of that work on customizing the Data Table widget(s), I realized that my Data Table Content Selector widget didn’t support all of the new features. If I wanted to have buttons or icons or customized reference links, I needed to tweak the code a little bit to provide that capability. Primarily, I needed to expand the schema for my configuration object to include options for buttons and reference pages for every table configuration. That would make the typical state value for a given table look something like this:

open: {
    filter: 'caller_idDYNAMIC90d1921e5f510100a9ad2572f2b477fe%5Eactive%3Dtrue',
    fields: 'number,opened_by,opened_at,short_description',
    btnarray: [],
    refmap: {sys_user: 'user_profile'}
},

To maintain backwards compatibility, both of the new options, btnarray and refmap, would need to be optional. Since the content selector widget relies on the URL-based version of the Data Table widget, implementing the new features was simply a matter of including them, if present, in the new URL at every page refresh:

function refreshPage(table, perspective, state) {
	var tableInfo = getTableInfo(table, perspective);
	var s = {};
	s.id = $location.search().id;
	s.table = tableInfo.name;
	s.filter = tableInfo[state].filter;
	s.fields = tableInfo[state].fields;
	s.buttons = '';
	if (tableInfo[state].btnarray && Array.isArray(tableInfo[state].btnarray) && tableInfo[state].btnarray.length > 0) {
		s.buttons = JSON.stringify(tableInfo[state].btnarray);
	}
	s.refpage = '';
	if (tableInfo[state].refmap) {
		s.refpage = JSON.stringify(tableInfo[state].refmap);
	}
	s.px = perspective;
	s.sx = state;
	var newURL = $location.search(s);
	spAriaFocusManager.navigateToLink(newURL.url());
}

That was basically all there was to it. Now I just need to create a new configuration object that takes advantage of these new features. My original example configuration contained two perspectives, Requester and Fulfiller. To show off the new buttons feature, I decided to add a third perspective, Approver, and then include three separate icons, one to Approve, one to Approve with comments, and another to Reject. The button configuration that I created to support this turned out like this:

btnarray: [
	{
		name: 'approve',
		label: 'Approve',
		heading: '-',
		icon: 'workflow-approved',
		color: 'success',
		hint: 'Click here to approve'
	},{
		name: 'approvecmt',
		label: 'Approve w/Comments',
		heading: '-',
		icon: 'comment-hollow',
		color: 'success',
		hint: 'Click here to approve with comments'
	},{
		name: 'reject',
		label: 'Reject',
		heading: '-',
		icon: 'workflow-rejected',
		color: 'danger',
		hint: 'Click here to reject'
	}
]

After entering some additional modifications to the configuration to add the new perspective, the resulting page ended up looking like this:

Approver perspective with Action Icons

That took care of the look and feel, but to make the buttons actually work, I needed to create another button handling widget to process the button clicks on the three icons that I had configured. For that, I just grabbed the example that I had created earlier and cloned it to create a new Approval Click Handler widget. Here is the client script:

function(spModal, $rootScope) {
	var c = this;
	$rootScope.$on('button.click', function(e, parms) {
		if (!c.data.inProgress) {
			c.data.inProgress = true;
			c.data.sys_id = parms.record.sys_id;
			c.data.action = parms.button.name;
			c.data.comments = '';
			if (c.data.action == 'reject' || c.data.action == 'approvecmt') {
				getComments(c.data.action);
			} else if (c.data.action == 'approve') {
				processDecision();
			}
			c.data.inProgress = false;
		}
	});

	function getComments(state) {
		var msg = 'Approval comments:';
		if (state == 'reject') {
			msg = 'Please enter the reason for rejection:';
		}
		spModal.prompt(msg, '').then(function(comments) {
			c.data.comments = comments;
			processDecision();
		});
	}

	function processDecision() {
		c.server.update().then(function(response) {
			window.location.reload(true);
		});
	}
}

… and here is the server side script:

(function() {
	if (input) {
		var current = new GlideRecord('sysapproval_approver');
		current.get(input.sys_id);
		if (current.state == 'requested') {
			current.state = 'approved';
			if (input.action == 'reject') {
				current.state = 'rejected';
			}
			var comments = 'Approval response from ' + gs.getUserDisplayName() + ':';
			comments += '\n\nDecision: ' + current.getDisplayValue('state');
			if (input.comments) {
				comments += '\nReason: ' + input.comments;
			}
			current.comments = comments;
			current.update();
		}
	}
})();

When I first pulled this up and tested the various buttons, a single click appeared to launch multiple iterations of the code. After entering comments in the modal pup-up box, another comment entry box would pop-up as if I had clicked on the icon a second time. Looking at the resulting records, the entered comments would often appear multiple times. On one example, it was entered 10 times! I never did figure out why that was happening, but I added conditionals to both the client side and server side scripts in an effort to put a stop to that behavior. That seems to have stopped it, but that still doesn’t explain to me why that is happening.

Looks like I have a little more testing to do before I put together a final Update Set …