In the Notes client, you often have a series of comboboxes where the
value in one, determines the list of choices in the next, a common
example being "Main Category", "Sub Category1", "Sub Category 2".
When doing this on the Web, using the built-in "refresh fields on
keyword change etc" feature, it works, but can cause the screen to
jump around as all the fields are refreshed.
I had a user who didn't like this, so this is the solution I came up
with that writes comboboxes dynamically, by looking at a hidden
field containing the data - a sort of pseudo-DBLookup in
JavaScript.....
Code
An alternative to using "refresh fields on keyword change" and
"refresh choices on document refresh" involves 4 parts
1) A Lookup view, that contains the values in a single column,
using a predefined separator - I use the pipe symbol |
2) A hidden lookup field on the form that does a dbcolumn on the above view
3) Some JavaScript to process the hidden field above
4) A field that contains the lookup value and a hotspot on the field
that triggers the above JavaScript
As follows
1) Create a view - for example, I called in "LookupStaffDivisions",
and it should have only one column, which contains multiple values
separated by a common separator. In my case I used the pipe symbol
'|' which is also in the JavaScript code. An e.g. of the column
contents is:
HR|Bob Jones
HR|Mike Smith
Admin|Sarah Joyce
Admin|Bill Clinton
2) Create a hidden field on the form that looks this up e.g.
<input type="hidden" name="lookupSomeValue"
value="[SOMECOMPUTEDFIELD]" >
Everything in the line above is passthru HTML. The
[SOMECOMPUTEDFIELD] is replaced with a field that is
computed when composed and contains a dbcolumn on some view. A
sample formula for the field is below:
(Note the space " " at the end of the value of t1 - this is needed
due to the counting starting at 0 in JavaScript)
Sample field value:
t1:=@DbColumn("":"Nocache" ;"" ; "LookupStaffDivisions" ; 1) : " ";
@Text(t1)
3) The JavaScript code (in the JSHeader)
function getLookupList( key, fieldToChange, fieldLookupValues ){
//take a field containing the list values and add them
//to an array
var inVal=fieldLookupValues;
var allValues=new Array();
var count=0;
var beg=0;
var end=0;
while (end!=-1){
end=inVal.indexOf(";", beg);
allValues[count]=inVal.substring(beg,end)
beg=end+1
count++
}
//get the number of documents in the array
var numOfDocs = count
var sLookupResult="";
var sCurrentValue="";
var k=0;
var returnValues=new Array();
//now parse the array looking for the key
for (i=0 ; i < numOfDocs ; i++ ){
sCurrentValue=allValues[i];
iFound=inStr(1, sCurrentValue.toLowerCase() , key.toLowerCase() );
if (iFound > 0 ){
sLookupResult=getEnd(sCurrentValue ,"|" )
returnValues[k]= sLookupResult;
k++;
}
}
//as we are working in base 0, subtract 1 from the total
max=k-1
/*depending on the field type that is being changed, display the
output. So far it's only set to work with comboboxes, as well as a
straight dump to the document if the field isn't found */
if ( fieldToChange == null ) {
//field not found, so output to the document - alternatively
you could
//write an error message. Normally I write the result into an IFrame.
document.open()
document.write("<table cellpadding='0' cellspacing='0'
border='0' bgcolor='#FEFEFE'> ")
for(k=0 ; k<max ; k++){
document.write( returnValues[k] )
}
document.write("</table>")
} else if ( inStr( 1, fieldToChange.type , "select" )) {
//the field type is combo box (html SELECT statement)
//reset the max number of options
fieldToChange.options.length=null
//update the combobox, check how many results are to be returned
if (max<1){
fieldToChange.options.length=1
fieldToChange.options[0].text = "None available"
}else{
//add 1 to max to allow the first item in the list to be
set to "Please select one"
fieldToChange.options.length=max + 1
//set the first option in the list to be "Please select one"
fieldToChange.options[0].text="Please select one"
//now add the results to the end of the combobox
for(k=0 ; k<max ; k++){
fieldToChange.options[k+1].text = returnValues[k]
}
}
}
}
/* The below are various Javascript equivalent of LotusScript
functions, taken from various sources - mostly from the
"Javascript Bible 3rd edition" by Danny Goodman*/
function inStr(beginning, word1, word2) {
check1 = new String(word2);
returnInStr = word1.indexOf(word2, (beginning - 1)) + 1;
return returnInStr;
}
function mid(inputMid, pos, l) {
pos = pos - 1;
if ((pos < inputMid.length) && ((pos + l) <=
inputMid.length)) {
returnMid = inputMid.substring(pos, pos + l); }
else { returnMid = ""; }
return returnMid;
}
function replaceSubstring (inputString, badString,
goodString, caseSensitive) {
fixedReplace = "";
UI = inputString;
UB = badString;
if ((caseSensitive != 1) && (caseSensitive != true)) {
UI = inputString.toUpperCase();
UB = badString.toUpperCase();
}
badEnd = -1;
badLoc = UI.indexOf(UB);
if (badLoc != -1) {
for (x=1; (badLoc != -1); x++) {
fixedReplace = fixedReplace +
inputString.substring((badEnd +
1), badLoc) + goodString
badEnd = badLoc + UB.length - 1;
badLoc = UI.indexOf(UB, (badLoc + 1)); }
fixedReplace = fixedReplace +
inputString.substring((badEnd + 1),
inputString.length); }
else { fixedReplace = inputString; }
return fixedReplace;
}
// similar to the StrLeft function
function getFront(mainStr, searchStr ){
foundOffset = mainStr.indexOf(searchStr)
if ( foundOffset == -1 ) {
return null;
}
return mainStr.substring(0, foundOffset );
}
// similar to the StrRight function
function getEnd(mainStr, searchStr ){
foundOffset = mainStr.indexOf(searchStr)
if ( foundOffset == -1 ) {
return null;
}
return mainStr.substring( foundOffset + searchStr.length, mainStr.length);
}
4) The code for the JavaScript hotspot, which causes the contents
of a combobox to be changed dynamically.
form=document.forms[0];
key=form.Division.options[form.Division.selectedIndex].text;
getLookupList( key, form.StaffList, form.lookupSomeValue.value)
In the above code, Division is the name of the first combobox, which
when selected changes the contents of the 2nd combobox which is
called StaffList, providing a quick way of doing a dblookup without
the issues of the screen jumping around when a refresh occurs.