Look-up Tables: Smart pick list example
31 August 2008Before I got sidetracked playing around with Kuali Rice, I had set out to create some kind of mechanism to place HTML controls on a form that would render an HTML select/option drop-down for small lists and a pop-up data picker for larger lists. My theory was that there was some point at which a list got to be too large to be effectively presented as a drop-down, and applications should be smart enough to recognize that threshold and make the transition from one kind of data selection method to another at run-time.
Regardless of what that number actually turns out to be (and my theory is that you should be able to adjust that number to suit your own tastes!), before the control is rendered on the page, the system should take a look at the size of the list, and then based on that size, make a determination as to the most appropriate type of control to be used for a list of that size. To demonstrate the idea, I placed a live example here. For the purposes of demonstration, I set the threshold to five, and have three lists to choose from: one of seven elements, one of two elements, and one with no elements.
To try it out, select one of the three lists from the drop-down and click on the “Create HTML control” button. If it is working as it should, the Data Type table should render out a pop-up pick list, and the other two should render out simple HTML select/option statements. The primary script that makes all of this work is picklist.js:
// picklist.js
var pickListConfig = {};
pickListConfig.threshhold = 5;
pickListConfig.control = [];
pickListConfig.table = {};
function setUpPickList(element, name, source, value, returnFunction) {
var index = pickListConfig.control.length;
var thisControl = {};
thisControl.element = document.getElementById(element);
thisControl.name = name;
thisControl.source = source;
thisControl.value = value;
thisControl.returnFunction = returnFunction;
pickListConfig.control[index] = thisControl;
pickListConfig.currentControl = index;
if (pickListConfig.table[source] != null) {
determinePickListApproach();
} else {
ajaxGet('/core/optlist/' + source + '.xml', 'processTableSize','tableSizeError');
}
}
function processTableSize(xmlDoc) {
var root = xmlDoc.documentElement;
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
pickListConfig.table[thisControl.source] = parseInt(root.attributes[0].value);
determinePickListApproach();
}
function tableSizeError(httpRequest) {
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
if (httpRequest.status == 404) {
pickListConfig.table[thisControl.source] = 0;
determinePickListApproach();
} else {
ajaxError(httpRequest);
}
}
function determinePickListApproach() {
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
var actualSize = pickListConfig.table[thisControl.source];
if (actualSize > pickListConfig.threshhold) {
buildPopUpPickList();
} else {
if (actualSize > 0) {
ajaxGetJson('/core/options/' + thisControl.source + '.js', 'buildDropDownPickList',
'ajaxError');
} else {
buildDropDownPickList(null);
}
}
}
function buildPopUpPickList() {
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
var html = '<input type="text" name="' + thisControl.name + 'Label" id="' + thisControl.name +
'Label" value="' + thisControl.value + '" readonly="true">\n';
html += '<input type="hidden" name="' + thisControl.name + '" id="' + thisControl.name +
'" value="' + thisControl.value + '">\n';
html += '<input type="submit" value="..." onclick="launchPopUpPickList(' + index + ')">\n';
thisControl.element.innerHTML = html;
if (thisControl.returnFunction > '') {
eval(thisControl.returnFunction + '();');
}
}
function buildDropDownPickList(options) {
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
var html = '<select name="' + thisControl.name + '">\n';
if (options != null && options.length > 0) {
for (var i=0; i<options.length; i++) {
html += ' <option value="' + options[i].value + '"';
if (options[i].value == thisControl.value) {
html += ' selected';
}
html += '>' + options[i].label + '</option>\n';
}
}
html += '</select>\n';
thisControl.element.innerHTML = html;
if (thisControl.returnFunction > '') {
eval(thisControl.returnFunction + '();');
}
}
function launchPopUpPickList(index) {
pickListConfig.currentControl = index;
var thisControl = pickListConfig.control[index];
var url = '/core/select.html?js=/core/optlistjs/' + thisControl.source +
'.js&fn=updateFormWithSelected';
var popupWindow = window.open(url, 'popupWindow', 'toolbar=no,directories=no,status=no,
scrollbars=yes,resizable=yes,resize=yes,menubar=no,height=500,width=600');
if (window.focus) {
popupWindow.focus();
}
return false;
}
function updateFormWithSelected(selected) {
if (selected != null) {
var index = pickListConfig.currentControl;
var thisControl = pickListConfig.control[index];
thisControl.value = selected.id;
document.getElementById(thisControl.name).value = selected.id;
document.getElementById(thisControl.name + 'Label').value = selected.description;
}
}
Basically, the script uses the /core/optlist/<lookupTableId>.xml file to determine the size of the table, and the branches to the appropriate function based on the comparison of the returned size to the specified threshhold. There are still some things that I would like to add one day, such as the ability to specify whether or not this was a required field, so that I could add a “nothing selected” option to the list for those that were not, but overall I think this provides the capability that I was originally looking for.
There still has to be some some function to set all of this in motion at the time that the page loads, so there is work yet to be done before it is really fully usable, but I think this is a good start.
Sorry, the comment form is closed at this time.





