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