“Learning from mistakes and constantly improving products is a key in all successful companies.”
— Bill Gates
When I first conceived of my Configurable Data Table Widget Content Selector, my main focus was on creating a process that would read the JSON configuration file and turn those configuration rules into a functioning widget in accordance with the specifications. That was an interesting challenge that I had a quite a bit of fun with, but I started out by hard-coding the configuration object at the beginning of the widget and I never went back and set things up so that you could reuse the widget with a different configuration. Obviously, that’s not very friendly; now I need to go back in and set things right. The configuration object that you want to use should be an external parameter that gets passed into the widget via some external source such as a URL parameter or widget option. Let’s see if we can’t fix that right now.
I think that the first thing that I want to do is to create a base class for the configuration object script. That will do two things: 1) provide a common foundation of code for all of the configuration objects that you would like to build, and 2) provide a way to identify all of the qualifying scripts as all scripts that extend this particular base class. We’ll call it the ContentSelectorConfig:
var ContentSelectorConfig = Class.create();
ContentSelectorConfig.prototype = {
initialize: function() {
},
getConfig: function(sp) {
return {
perspective: this.perspective,
state: this.state,
table: this.table
};
},
type: 'ContentSelectorConfig'
};
With our base class established, I can now hack up my earlier configuration object and make it an extension of this new base class:
var MyTaskConfig = Class.create();
MyTaskConfig.prototype = Object.extendsObject(ContentSelectorConfig, {
initialize: function() {
},
perspective: [...],
state: [...],
table: {...},
type: 'MyTaskConfig'
});
For now, I am just going to reuse the list of perspectives, states, and tables that I was using before and focus on the mechanics of making this configuration an external parameter rather than a hard-coded reference. Rather than make the changes to my original My Data widget, though, I decided to clone the widget, give it a new name, and leave the original widget as is. I called my new widget Content Selector, and it started out life as an exact copy of the My Data widget before I started to hack it up.
The first thing that I did was to add a new option to the Option Schema so that we could pass in the name of the ContentSelectorConfig that we want to use. We already had an existing option to display the widget content in a single row rather than a stacked block, so this was just a matter of adding a second option to the existing array of options.
[{
"hint":"Mandatory configuration script that is an extension of ContentSelectorConfig",
"name":"configuration_script",
"section":"Behavior",
"label":"Configuration Script",
"type":"string"
},{
"hint":"If selected, will display the widget content in a single row rather than a stacked block",
"name":"display_inline",
"default_value":"false",
"section":"Presentation",
"label":"Display Inline",
"type":"boolean"
}]
Now that our new option has been defined, it’s time to rewrite the code that pulled in the hard-coded configuration object. Here is the original version of the first few lines of code in the server side script:
var mdc = new MyDataConfig();
data.config = mdc.getConfig($sp);
data.config.authorizedPerspective = getAuthorizedPerspectives();
establsihDefaults();
data.user = data.user || {sys_id: gs.getUserID(), name: gs.getUserName()};
data.inline = false;
if (options && options.display_inline == 'true') {
data.inline = true;
}
We are still going to want to establish the data.config object, but we are going to want to do it using an instance of the class named in our new Option. Last year, when I was working on my Static Monthly Calendar, I needed to turn a class name into an object of that class, and I built a little tool for that, which I called the Instantiator. We can use that same tool here to turn the name of our configuration script into an instance of that class that we can use to pull in the configuration. Here is the restructured code to start out our updated widget:
data.config = {};
data.inline = false;
data.user = data.user || {sys_id: gs.getUserID(), name: gs.getUserName()};
if (options) {
if (options.configuration_script) {
var instantiator = new Instantiator();
instantiator.setRoot(this);
var configurator = instantiator.getInstance(options.configuration_script);
data.config = configurator.getConfig($sp);
data.config.authorizedPerspective = getAuthorizedPerspectives();
establsihDefaults();
}
if (options.display_inline == 'true') {
data.inline = true;
}
}
Now we just need to throw it on a page with a Data Table widget, configure the options, and give it a spin. After dragging all of the widgets onto the page in the Page Designer, clicking on the pencil icon in the upper right-hand corner of our update widget will bring up the Options dialog where we can specify our configuration script.
Once the widget Options have been specified, all we need to do is to pull up the page and see if things are still functioning as they should, which appears to be the case.
Well, that’s about all there is to that. Basically, it does exactly what it did before, but you can now specify the configuration script using the Widget Options instead of having it hard-coded in the script as it was in the original version. Here’s an Update Set with the modifications if you’d like to play around with it on your own.