Scripted Value Columns in the SNH Data Table Widgets

“Daring ideas are like chessmen moved forward; they may be beaten, but they may start a winning game.”
Johann Wolfgang von Goethe

Every once in a while, I go out to the Developer’s Forum, just to see what other folks are talking about or struggling with. I rarely comment; I leave that to people smarter or faster than myself. But occasionally, the things that people ask about will trigger a thought or idea that sounds interesting enough to pursue. The other day there were a couple of posts related to the Data Table widget, something that I spent a little time playing around with over the years, and it got me to wondering if I could do a little something with my SNH Data Table Widgets to address some of those requirements. One individual was looking to add catalog item variables to a table and another was looking to add some data from the last comment or work note on an Incident. In both cases, the response was essentially that it cannot be done with the out-of-the-box data table widgets. I never did like hearing that as an answer.

It occurred to me that these and other similar columns just needed a little code to fish out the values that they wanted to have displayed on the table with the rest of the standard table fields. We are already doing something like that with the aggregate columns, so it didn’t seem that much of a stretch to clone some of that code and adapt it to handle these types of requirements. If we took the stock properties for aggregate columns and buttons & icons (label, name, and heading) and added one more for the name of a Script Include, as the data was loaded from the base table, we could pass the row data and the column configuration to a standard function in that Script Include to obtain the value for that column. You know what I always ask myself: How hard could it be?

So here is the plan: create a new configuration option called Scripted Value Columns, update the configuration file editor to maintain the properties for those columns, and then update the Data Table widgets to process them based on the configuration. When the data for the table is loading, we’ll get an instance of the Script Include specified in the configuration and then call the function on that instance to get the value for the column. Sounded simple enough to me, but let’s see if we can actually make it work.

To begin, let’s create an example Script Include that we can use for testing purposes. At this point, it doesn’t matter where or how we get the values. We can simply return random values for now; we just want something that returns something so that we can demonstrate the concept. Here is the ScriptedValueExample that I came up with for this purpose.

var ScriptedValueExample = Class.create();
ScriptedValueExample.prototype = {
	initialize: function() {
	},

	getScriptedValue: function(item, config) {
		return Math.floor(Math.random() * 100) + '';
	},

	type: 'ScriptedValueExample'
};

The function that we will be calling from the core Data Table widget will be getScriptedValue. In the editor, our pick list of Script Includes can be limited to just those that contain the following text:

getScriptedValue: function(item, config)

This will mean that the function in your custom Script Include will need to have the exact same spacing and argument naming conventions in order for it to show up on the list, but if you clone the script from the example, that shouldn’t be a problem.

Now that we have our example script, we can jump over to the list of portal widgets and pull up one of the existing pop-up configuration editors and clone it to create our new Scripted Value Column Editor. For the HTML portion, we can keep the label, name, and heading fields, delete the rest, and then add our new script property.

<div>
  <form name="form1">
    <snh-form-field
      snh-model="c.widget.options.shared.label"
      snh-name="label"
      snh-required="true"/>
    <snh-form-field
      snh-model="c.widget.options.shared.name"
      snh-name="the_name"
      snh-label="Name"
      snh-required="true"/>
    <snh-form-field
      snh-model="c.widget.options.shared.heading"
      snh-name="heading"/>
    <snh-form-field
      snh-model="c.widget.options.shared.script"
      snh-name="script"
      snh-type="reference"
      snh-required="true"
      placeholder="Choose a Script Include"
      table="'sys_script_include'"
      display-field="'name'"
      value-field="'api_name'"
      search-fields="'name'"
      default-query="'scriptLIKEgetScriptedValue: function(item, config)'"/>
  </form>
  <div style="width: 100%; padding: 5px 50px; text-align: right;">
    <button ng-click="cancel()" class="btn btn-default ng-binding ng-scope" role="button" title="Click here to cancel this edit">Cancel</button>
    &nbsp;
    <button ng-click="save()" class="btn btn-primary ng-binding ng-scope" role="button" title="Click here to save your changes">Save</button>
  </div>
</div>

The default-query attribute of the sn-record-picker will limit our list of Script Includes to just those that will work as scripted value providers. Other than that, this pop-up editor will be very similar to all of the others that we are using for the other types of configurable columns.

There is no Server script needed for this one, and the Client script is the same as the one from which we made our copy, so there are no changes needed there.

function ScriptedValueColumnEditor($scope, $timeout, spModal) {
	var c = this;

	$scope.spModal = spModal;

	$scope.cancel = function() {
		$timeout(function() {
			angular.element('[ng-click*="buttonClicked"]').get(0).click(); 
		});
	};

	$scope.save = function() {
		if ($scope.form1.$valid) {
			$timeout(function() {
				angular.element('[ng-click*="buttonClicked"]').get(1).click(); 
			});
		} else {
			$scope.form1.$setSubmitted(true);
		}
	};

	$timeout(function() {
		angular.element('[class*="modal-footer"]').css({display:'none'});
	}, 100);
}

So that takes care of that. Now we need to modify the main configuration editor to utilize this new pop-up widget. That sounds like a good project for our next installment.