Solved

Simple example code of a AJAX replacement for @DbColumn and @Lookup.

Posted on 2007-11-27
39
1,613 Views
Last Modified: 2013-12-18
Hi

I'm working on my1st Notes/Domino web app.  

I'm after a good, and hopefully simple/clear AJAX example of dynamically populating the options of combo boxes and computed fields (from documents in a view), based on the selection of a dialog box.

I have done it with @ functions, but having a few annoying problems and I'm told AJAX is much better.

Current examples:-

"<SELECT DOCUMENT TYPE>":@Unique(@DbColumn("":"nocache"; ""; "Templates"; 1))

"<SELECT LOCATION>":@Unique(@DbColumn("":"nocache"; ""; "Locations"; 2))

"<SELECT DEPARTMENT>":@DbLookup("":"NoCache";"":""; "Departments";location;"Department";[FailSilent] )

@DbLookup("":"NoCache";"":""; "Location And Departments";location+ " " + department;"DepartmentApprover";[FailSilent] )

I've googled, but struggle to find anything simple and understandable (well, for a web novice dunce like me). I've been generous with the points hoping for a really good clear example.

Thanks
0
Comment
Question by:IanWood
  • 20
  • 16
  • +2
39 Comments
 
LVL 22

Accepted Solution

by:
Bill-Hanson earned 500 total points
Comment Utility
(1) There is no simple AJAX example.
(2) It is MUCH better that making a round trip to the server for the whole page.
(3) It is worth the extra effort (for your users and your server).

I have a working example for you, but first, you will need some basic functions that make things easier later.  Paste these functions into the form's "JS Header" module, or even better, put them in a common JS library.

Continued in next post...
// Gets a handle to an XMLHTTP object (the object that makes AJAX possible).

function getXmlHttpObject(){

	try{

		// Firefox, Opera 8.0+, Safari

		return new XMLHttpRequest();

	}catch(e){

		// Internet Explorer

		try{

			return new ActiveXObject("Msxml2.XMLHTTP");

		}catch (e){

			try{

				return new ActiveXObject("Microsoft.XMLHTTP");

			}catch (e){

				return null;

			};

		};

	};

};
 

// This function simply hides some of the setup required to use the XMLHTTP object.

function sendXmlHttpRequest(xmlHttp, url, fn){

	if (fn) xmlHttp.onreadystatechange = fn;

	xmlHttp.open("GET", url, (fn != null));

	xmlHttp.send(null);

};
 

// Synchronously retrieves a Lotus Notes view as an XML document.

function dbGetViewXmlDocument(dburl, view, params){

	try{

		var xmlHttp = getXmlHttpObject();

		var url = dburl + "/" + view + "?ReadViewEntries";

		if ((params != null) && (params != "")) url = url + "&" + params;

		sendXmlHttpRequest(xmlHttp, url, null)

		return xmlHttp.responseXML.documentElement;

	}catch(e){

		throw new Error(e.message);

	};

};
 

// Gets a page element by id.

function getElementById(id, doc){

	doc = (doc?doc:document);

	var retval = null;

	if(doc.getElementById){

		retval = doc.getElementById(id);

	}else if(doc.all){

		retval = doc.all[id];

	}else if(doc.layers){

		retval = doc.layers[id];

	};

	return retval;

};
 

// Gets the inner text of any XML document node.

function getXMLNodeInnerText(node){

	var retval = "";

	if (typeof node.textContent != 'undefined'){

		retval = node.textContent;

	}else if (typeof node.innerText != 'undefined'){

		retval = node.innerText;

	}else if (typeof node.text != 'undefined'){

		retval = node.text;

	}else{

		switch (node.nodeType){

			case 3:

			case 4:

				return node.nodeValue;

				break;

			case 1:

			case 11:

				var innerText = '';

				for (var i = 0; i < node.childNodes.length; i++){

					innerText += getXMLNodeInnerText(node.childNodes[i]);

				};

				retval = innerText;

				break;

			default:

				retval = "";

		};

	};

	if (strLeft(retval, 1) == "\n") retval = strRight(retval, retval.length-1);

	return retval;

};
 

// Extracts a specified number of the leftmost characters in a string.

function strLeft(s, n){

	s = new String(s);

	if(n <= 0) return "";

	else if(n > String(s).length) return s;

	else return String(s).substring(0, n);

};
 

// Extracts a specified number of the rightmost characters in a string.

function strRight(s, n){

	if(n <= 0) return "";

	else if(n > String(s).length) return s;

	else{

		var iLen = String(s).length;

		return String(s).substring(iLen, iLen - n);

	};

};

Open in new window

0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
... Continued from last post ...

Next, add this to the "onLoad" module in your form...

initPage();

Finally, in the form's "JS Header" module, just paste this function (initPage) and modify it as required.  Also, in the Domino Designer, remember to set the Id tag under the field's HTML properties.  That should get you started!


function initPage(){

	var maxResults = 1000;

	var dbURL = "http://your.server.com/db.nsf";

	var viewName = "SomeView";

	var columnNumber = 1;

	var fieldName = "UserName";

	var xmlDoc = dbGetViewXmlDocument(dbURL, viewName, "Count=" + maxResults);

	var viewEntries = xmlDoc.getElementsByTagName("viewentry");

	var values = new Array();

	if(viewEntries.length == 0){

			values[values.length] = "ERROR: No Choices Found!";

		}else{

			for(var row=0; row < viewEntries.length; row++){

				var value = getXMLNodeInnerText(viewEntries[row].getElementsByTagName("entrydata")[columnNumber]);

				values[values.length] = value;

			};

	};

	var select = getElementById(fieldName);

	select.options.length = 0;

	for(var i=0; i < values.length; i++){

		select.options[i] = new Option(values[i],values[i]);

	};

};

Open in new window

0
 
LVL 19

Expert Comment

by:madheeswar
Comment Utility
Bill,
That's a good work.
0
 

Author Comment

by:IanWood
Comment Utility
Thanks for that, looks great.

I'll have a go later and try it out....

0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
Thanks, madheeswar.  My ultimate goal is to design a set of JS classes specifically for Domino.  When it's done, I'll post it to OpenNTF.

Ian, thanks.  Take your time.
0
 
LVL 31

Expert Comment

by:qwaletee
Comment Utility
Bill,

Nathan and the gang have already been working on an extensive Ajax framework for Domino. However, it is fairly heavy (it uses a heavy underlying framework for complete Ajax UI and back end interfaces), so a lightweight library for use in "solution bits" would probably be most welcome.
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
Right, I think they are basing theirs on EXT.  I plan to design a stand-alone library with a very basic GUI.  I never seem to have the time, though.  
0
 

Author Comment

by:IanWood
Comment Utility
Hi Quick update.  I've been busy with other work stuff and haven't had a chance to try it yet.   Hopefully i'll be making a start this afternoon....

0
 

Author Comment

by:IanWood
Comment Utility
Right, I've had a go, but getting a JS error message...

'Options' is null or not an object
Code;0

It's obviosuly not found the field it was supposed to.   I've no doubt done something wrong somewhere..

Is "fieldname" the field that is being provided with the options?

And "viewentry" the field that's beeing looked up in the view?

What about "entrydata"?

Thanks and apologies for being slow!
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
JavaScript is case-sensitive.

The error is probably happening on this line:

select.options.length = 0;

Make sure that in your code, "options" is lower case.
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
Oops, I didn't finish reading your post...

Is "fieldname" the field that is being provided with the options?

 - YES

And "viewentry" the field that's being looked up in the view?

 - NO - "viewentry" is a tag name in the ReadViewEntries XML.  You should not be changing that part.

This should clear things up a bit.  Here's a couple of new functions to add to your library.

Using these functions, the initPage function can be re-written as:

function initPage(){
      var values = dbColumn("http://mistest.mainline.com/names.nsf", "($Users)", 2, 5);
      setSelectOptions("UserName", values);
};
function dbColumn(dbURL, viewName, columnNumber, maxResults){

	var xmlDoc = dbGetViewXmlDocument(dbURL, viewName, "Count=" + maxResults);

	var viewEntries = xmlDoc.getElementsByTagName("viewentry");

	var values = new Array();

	if(viewEntries.length == 0){

			values[values.length] = "ERROR: No Choices Found!";

		}else{

			for(var row=0; row < viewEntries.length; row++){

				var value = getXMLNodeInnerText(viewEntries[row].getElementsByTagName("entrydata")[columnNumber]);

				values[values.length] = value;

			};

	};

	return values;

};
 

function setSelectOptions(fieldName, values){

	var select = getElementById(fieldName);

	select.options.length = 0;

	for(var i=0; i < values.length; i++){

		select.options[i] = new Option(values[i],values[i]);

	};

};

Open in new window

0
 

Author Comment

by:IanWood
Comment Utility
Thanks again.

I'm still a little confused though,  What tells it what value (i.e. field) you want to lookup in the view?  

function dbColumn(dbURL, viewName, columnNumber, maxResults)

Presumably columnNumber is the column whose values are returned, but where's the key value you want looking up?

I'm probably missing something somewhere.  I'll increase the points when i accept it, for the extra help getting it working.
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
This is an example of @DbColumn which returns an entire column.  For @DbLookup, we need another function that uses the RestrictToCategory URL parameter to match documents by key.

Here's the @DbLookup function in JavaScript.
function dbLookup(dbURL, viewName, key, columnNumber, maxResults){

	var xmlDoc = dbGetViewXmlDocument(dbURL, viewName, "RestrictToCategory=" + key + "&Count=" + maxResults);

	var viewEntries = xmlDoc.getElementsByTagName("viewentry");

	var values = new Array();

	if(viewEntries.length == 0){

			values[values.length] = "ERROR: No Choices Found!";

		}else{

			for(var row=0; row < viewEntries.length; row++){

				var value = getXMLNodeInnerText(viewEntries[row].getElementsByTagName("entrydata")[columnNumber]);

				values[values.length] = value;

			};

	};

	return values;

};

Open in new window

0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
A couple of notes about my last post...

There are a couple of differences in the way that the JavaScript version of dbLookup works compared to @DbLookup.

(1) The view must be categorized.  Just sorting the first column is not enough.
(2) The columnNumber parameter is indexed starting from the column immediately after the first categorized column.  For example, if you wanted to get a list of all of your servers for a specific domain, you would call

values = dbLookup("http://server.com/names.nsf", "Servers", "SOME_DOMAIN", 1, 500);

In the "Servers" view, "Server Name" is actually the 3rd column, but it is the 2nd one after our key column, and since our columnNumber parameter is zero-based, we pass 1 to dbLookup as the column to return.
0
 

Author Comment

by:IanWood
Comment Utility
Thanks.  

I'm still getting the error message:-   "options is null or not an object"

Is it failing to find/use the view properly?   Should a view for dbcolumn be setup the same as the lookup (i.e. categorised and indexed from 0)

Would it being a https make any difference?

I've included the full code below.
// Gets a handle to an XMLHTTP object (the object that makes AJAX possible).

function getXmlHttpObject(){

        try{

                // Firefox, Opera 8.0+, Safari

                return new XMLHttpRequest();

        }catch(e){

                // Internet Explorer

                try{

                        return new ActiveXObject("Msxml2.XMLHTTP");

                }catch (e){

                        try{

                                return new ActiveXObject("Microsoft.XMLHTTP");

                        }catch (e){

                                return null;

                        };

                };

        };

};

 

// This function simply hides some of the setup required to use the XMLHTTP object.

function sendXmlHttpRequest(xmlHttp, url, fn){

        if (fn) xmlHttp.onreadystatechange = fn;

        xmlHttp.open("GET", url, (fn != null));

        xmlHttp.send(null);

};

 

// Synchronously retrieves a Lotus Notes view as an XML document.

function dbGetViewXmlDocument(dburl, view, params){

        try{

                var xmlHttp = getXmlHttpObject();

                var url = dburl + "/" + view + "?ReadViewEntries";

                if ((params != null) && (params != "")) url = url + "&" + params;

                sendXmlHttpRequest(xmlHttp, url, null)

                return xmlHttp.responseXML.documentElement;

        }catch(e){

                throw new Error(e.message);

        };

};

 

// Gets a page element by id.

function getElementById(id, doc){

        doc = (doc?doc:document);

        var retval = null;

        if(doc.getElementById){

                retval = doc.getElementById(id);

        }else if(doc.all){

                retval = doc.all[id];

        }else if(doc.layers){

                retval = doc.layers[id];

        };

        return retval;

};

 

// Gets the inner text of any XML document node.

function getXMLNodeInnerText(node){

        var retval = "";

        if (typeof node.textContent != 'undefined'){

                retval = node.textContent;

        }else if (typeof node.innerText != 'undefined'){

                retval = node.innerText;

        }else if (typeof node.text != 'undefined'){

                retval = node.text;

        }else{

                switch (node.nodeType){

                        case 3:

                        case 4:

                                return node.nodeValue;

                                break;

                        case 1:

                        case 11:

                                var innerText = '';

                                for (var i = 0; i < node.childNodes.length; i++){

                                        innerText += getXMLNodeInnerText(node.childNodes[i]);

                                };

                                retval = innerText;

                                break;

                        default:

                                retval = "";

                };

        };

        if (strLeft(retval, 1) == "\n") retval = strRight(retval, retval.length-1);

        return retval;

};

 

// Extracts a specified number of the leftmost characters in a string.

function strLeft(s, n){

        s = new String(s);

        if(n <= 0) return "";

        else if(n > String(s).length) return s;

        else return String(s).substring(0, n);

};

 

// Extracts a specified number of the rightmost characters in a string.

function strRight(s, n){

        if(n <= 0) return "";

        else if(n > String(s).length) return s;

        else{

                var iLen = String(s).length;

                return String(s).substring(iLen, iLen - n);

        };

};
 

function dbColumn(dbURL, viewName, columnNumber, maxResults){

        var xmlDoc = dbGetViewXmlDocument(dbURL, viewName, "Count=" + maxResults);

        var viewEntries = xmlDoc.getElementsByTagName("viewentry");

        var values = new Array();

        if(viewEntries.length == 0){

                        values[values.length] = "ERROR: No Choices Found!";

                }else{

                        for(var row=0; row < viewEntries.length; row++){

                                var value = getXMLNodeInnerText(viewEntries[row].getElementsByTagName("entrydata")[columnNumber]);

                                values[values.length] = value;

                        };

        };

        return values;

};

 

function setSelectOptions(fieldName, values){

        var select = getElementById(fieldName);

        select.options.length = 0;

        for(var i=0; i < values.length; i++){

                select.options[i] = new Option(values[i],values[i]);

        };

};
 

function dbLookup(dbURL, viewName, key, columnNumber, maxResults){

        var xmlDoc = dbGetViewXmlDocument(dbURL, viewName, "RestrictToCategory=" + key + "&Count=" + maxResults);

        var viewEntries = xmlDoc.getElementsByTagName("viewentry");

        var values = new Array();

        if(viewEntries.length == 0){

                        values[values.length] = "ERROR: No Choices Found!";

                }else{

                        for(var row=0; row < viewEntries.length; row++){

                                var value = getXMLNodeInnerText(viewEntries[row].getElementsByTagName("entrydata")[columnNumber]);

                                values[values.length] = value;

                        };

        };

        return values;

};
 

function initPage(){

      var values = dbColumn("https://webmail.eu.something.com/mailin/hrukdocapproval.nsf", "(Locations)", 0, 50);

      setSelectOptions("Location2", values);

};

Open in new window

0
 

Author Comment

by:IanWood
Comment Utility
And how do I dynamically refresh any fields I need when an option is selected?
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
(1) I'm still getting the error message:-   "options is null or not an object".

When you call "setSelectOptions", The "getElementById" function is not finding your field.  Did you make sure to set the HTML ID for the field in the designer?  This is important for the code to work cross-browsers.  Have you run this in a debugger to see what the value of the "select" variable is in the "setSelectOptions" function?  If you don't have a JavaScript debugger, you need to get one!  I recommend Firebug for Firefox.  It's free, and it's the best.

(2) Is it failing to find/use the view properly?

Probably not.  The "options" object is not used for locating the view.

(3) Should a view for dbcolumn be setup the same as the lookup (i.e. categorised and indexed from 0)

No. I explained that above, but I was not very clear.  For dbColumn, the return column is zero-based starting from the first column in the view.  For dbLookup, the return column is 1-based and starts after the key column rather than the first column in the view.  When using dbLookup, experiment with different return column indexes until you find the column you need.

(4) Would it being a https make any difference?

No

(5) I've included the full code below.

Everything looks fine.  I'd check the HTML ID property of all fields on your form to make sure that they are all set.  The HTML ID should always be set to the field's name.

(6) And how do I dynamically refresh any fields I need when an option is selected?

Add code to the onChange event for the controller-field.  Here's an example:

      var value = getFieldValue("CONTROLLER_FIELD");
      var values = dbLookup("https://webmail.eu.something.com/mailin/hrukdocapproval.nsf", "SomeView", value, 1, 50);
      setSelectOptions("DEPENDANT_FIELD", values);

This requires some additions/changes to your library, but I've posted all of the code below.

IMPORTANT:  I've posted a new version of "setSelectOptions".  Be sure to replace your function with this new version.

(7) Bottom Line

You're close.  It looks to me like you only need to add the HTML ID to your fields then setup the controller-field to dependant-picklist relationship by coding the onChange event of the controller-field.

Paste these new functions into your JS Library.  Be sure to remove the old version of "setSelectOptions".
/**

* Returns the index of the given item's first occurrence.

* @param elt Element to locate in the array.

* @param from The index at which to begin the search. Defaults to 0.

* @return The first index at which a given element can be found in the array, or -1 if it is not present.

*/

if (!Array.prototype.indexOf){

  Array.prototype.indexOf = function(elt /*, from*/){

    var len = this.length;

    var from = Number(arguments[1]) || 0;

    from = (from < 0) ? Math.ceil(from) : Math.floor(from);

    if (from < 0) from += len;

    for (; from < len; from++){

      if (from in this && this[from] === elt) return from;

    };

    return -1;

  };

};
 

/**

* Gets a handle to the specified field.

* The field parameter can be a field object or the id of a field object.

* @param field An object handle (field) or an object id (string).

* @param form The form that contains the field (default is the first form).

*/

function getField(field, form){

	if(field == null) throw new Error("getField: Field cannot be null");

	form = (form?form:document.forms[0]);

	var retval = field;

	if (typeof(field) == "string"){

		retval = eval('form.' + field);

		if (retval == null) throw new Error("getField: Unable to locate field: " + field);

	};

	return retval;

};
 

function setSelectOptions(field, values, form){

	var select = getField(field, form);

	select.options.length = 0;

	for(var i=0; i < values.length; i++){

		select.options[i] = new Option(values[i],values[i]);

	};

};
 

function getSelectOptions(field, form){

	var select = getField(field, form);

	var retval = new Array();

	for(var i=0; i < select.options.length; i++){

		retval[retval.length] = select.options[i].value;

	};

	return retval;

};
 

/**

* Return the value of a field.

* @param field handle to a field element

* @param form The form that contains the field. Optional.

*/

function getFieldValue(field, form){

	field = getField(field, form);

	switch(field.type){

		case "text" :

		case "textarea" :

		case "password" :

		case "hidden" :

			return field.value;

		case "select-one" :

			var i = field.selectedIndex;

			if (i == -1) return "";

			else return (field.options[i].value == "") ? field.options[i].text : field.options[i].value;

		case "select-multiple" :

			var allChecked = new Array();

			for(i = 0; i < field.options.length; i++){

				if(field.options[i].selected){

					allChecked[allChecked.length] = ((field.options[i].value == "") ? field.options[i].text : field.options[i].value);

				};

			};

			return allChecked;

		case "button" :

		case "reset" :

		case "submit" :

			return "";

		case "radio" :

		case "checkbox" :

			if (field.checked) {return field.value; }else{ return "";};

		default :

			if (field.length > 1){

				if(field[0].type == "radio"){

					for (i = 0; i < field.length; i++){

						if (field[i].checked) return field[i].value;

					};

					return "";

				}else if(field[0].type == "checkbox"){

					var allChecked = new Array();

					for(i = 0; i < field.length; i++){

						if(field[i].checked) allChecked[allChecked.length] = field[i].value;

					};

					return allChecked;

				}else{

					alert("getFieldValue: Unrecognized field type for field " + field[0].name + ".");

				};

			}else{

				alert("getFieldValue: Unrecognized field type for field " + field.name + ".");

			};

		break;

	};

	return "";

};
 

/**

* Sets the value of a field.

* @param field handle to a field element

* @param val the value to set

* @param form The form that contains the field. Optional.

*/

function setFieldValue(field, val, form){

	field = getField(field, form);

	switch(field.type){

		case "text" :

		case "textarea" :

		case "password" :

		case "hidden" :

			field.value = val;

			break;

		case "select-one" :

			var options = getSelectOptions(field);

			field.options.selectedIndex = options.indexOf(val);

			break;

		case "select-multiple" :

			var lstValues = val.split('; ');

			var options = getSelectOptions(field);

			for (var x in lstValues){

			 	var index = options.indexOf(values[x]);

				if(index != -1){

					field.options[index].selected = true;

				};

			};

			break;

		case "button" :

		case "reset" :

		case "submit" :

			return;

		case "radio" :

		case "checkbox" :

			field.value = val;

			break;

		default :

			if(field[0].type == "radio"){

				for (i = 0; i < field.length; i++){

					if(val == field[i].value) field[i].checked = true;

					else field[i].checked = false;

				};

				return;

			}else if(field[0].type == "checkbox"){

				for(i = 0; i < field.length; i++){

					if(val[i]) field[i].checked = true;

					else field[i].checked = false;

				};

				return;

			}else{

				alert("Unrecognized field type for field " + field.name + ".");

			};

			break;

	};

	return;

};

Open in new window

0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
If you need to debug your code, try Firefox with the DOM inspector and Firebug installed (add-ons). The DOM Inspector should be activated when installing Firefox for the first time. Firebug can be downloaded and installed.

Nifty code, Bill !!
0
 

Author Comment

by:IanWood
Comment Utility
Brilliant!!  Thanks.  Again.  

I haven't had a lot of time, but I'm getting there.  I've got a dbcolumn working, just need to do the refresh changes and do the lookup.  :-)

One quick question, depending on form status, the fileds are sometimes hidden (and computed for display fields shown instead, to prevent editing.  I know i can use authors fields, i am, but at certain stages people need to be able to approve/reject etc, but not actually change the details).  

Will I have to build some check in to not do the lookup when the dropdown fields are not being used?

0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
Yes.
0
 

Author Comment

by:IanWood
Comment Utility
I've finally had a chance to spend some real time on this.  Sorry for the delay.  The code is working beautifully. Many thanks!!  :-)

It doesn't work with my old lotusscript validation routine, but I figure it's best to redo it in javascript anyway now.   Give the server an easier time!

I'll also need to make it take into account whether the fields involved are displayed or hidden 1st, but hopefully that should be easy enough.

I'll start a couple of new questions.  

Thansk again.  Brilliant code/answer.   Very helpful.
0
 

Author Closing Comment

by:IanWood
Comment Utility
Brilliant.  Many thanks. :-)
0
 

Author Comment

by:IanWood
Comment Utility
I've just about got it all working as I'd like now and I have to say, it's very slick.

One thing though, how do I go about keeping the selected values on a page load/reload?  Currently it wipes the selected choice and presents the options again.

I guess i need to store the value upon opening the document and then compare that to each retrieved value and if they match make it the selected value.  

Any suggestions?  My javascript knowledge isn't the best amd I'm been struggling to get it right.

I can open a new question if needs be, but you've mentioned not minding helping previously, so thought I'd just keep it here...
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
You just need to make sure that the field's current values are always in the field's options array.
The value is being wiped out because the options are not loaded until after Domino renders the form.  To prevent this, make sure that the formula for choices includes @ThisValue.
0
 

Author Comment

by:IanWood
Comment Utility
Thanks.   I'm not sure how you mean..   I don't have a formula for choices.  They're being populated by the AJAX code.

I just had "LOADING" in there which is replaced once the page loads.

I've changed it to formula and @ThisValue, but it still gets wiped.   Any ideas?
0
 

Author Comment

by:IanWood
Comment Utility
Also...  The drop down fields aren't always present.  I changed the init code to only perform the lookups dependant on document status, but that doesn't help if the document is in read mode, or the user isn'y an allowed author.

How can i check if the field is prssent/visible and editable?

Sorry for being a pain.   It's much appreciated.
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
The only thing I can think of is the choices formula.  If that does not contain the current field value(s) then Domino will wipe the current field value out since it is not valid.  For a combo-box using regular @DbLookups, I use a formula like this:
@If(!@IsDocBeingEdited; @Return(@ThisValue); "");

choices := @DbLookup("":"NoCache"; ""; "PicklistValues.Lookup"; pl_LookupKey; 2);

@If(@IsError(choices); "No Choices"; @Trim(@Unique(choices : @ThisValue)));

Open in new window

0
 

Author Comment

by:IanWood
Comment Utility
Thanks.   Oh... maybe that's it.  I haven't actually got any lookup forumla/choices, they're dynamically populated with AJAX.  Which now I think about it, I probably don't need except to lookup dependant choices on a keyword change.

I think I might have misunderstood originally and over ajaxed the pudding

I'll try adding the foumla back in for the static lookups, so it actually has a list to find the selected value from   One question.   Say field 2's choices get looked up when field 1 changes. Does field 2 also need to have a formula producing the same values that the Ajax lookup provides?

I hope that makes somke sort of sense.    
 
0
 

Author Comment

by:IanWood
Comment Utility
I think that might also have helped my only lookup when editing problem too.    I'm populating a couple of fields with javascript in initpage() via onload.  Hence having problems with looking up at the wrong time, they should just be noraml formula lookups and when they change the AJAX triggers.

Sorry, that was quite dumb of me.  
0
 

Author Comment

by:IanWood
Comment Utility
It's sorted.  :-)

Many thanks.  
0
 

Author Comment

by:IanWood
Comment Utility
Hope I'm not taking the mick too much, but got another question..  

Each button now does the following:-

@SetField("NewStatus";"02");
@Command([FileSave]);
@Command([FileCloseWindow])

My Lotusscript agent (running from WebQuerySave), gets the newStatus value fine and uses that to decide what to do.  That's fine  

But, my Validate function (using document.forms[0].NewStatus.value) called on OnSubmit doesn't.  It gets what was previously on the form (i,e not the "02" from the button).  I could really do with having the NewStatus value in the validate function.  

Any ideas?
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
I'm not sure if this will work, but you could try switching the button to JavaScript.

document.forms[0].NewStatus.value = "02";
document.forms[0].submit();
0
 

Author Comment

by:IanWood
Comment Utility
Thanks.  

The javascript version bypasses onSubmit and my validation rountine completely for some reason.  Any ideas?


0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
You could do something like this:

document.forms[0].NewStatus.value = "02";
if(document.forms[0].onsubmit()) document.forms[0].submit();
0
 

Author Comment

by:IanWood
Comment Utility
Good news is that it called the onSublit validate function and picked up the new value, but the WebQuerySave Lotusscript agent picked up the old value instead.  

I got my hopes up for a minute.  Bloody typical. lol.  

Any thoughts?
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
Strange.  I'll have to run some tests and get back to you.
0
 

Author Comment

by:IanWood
Comment Utility
Sussed it.  Sorry, my fault... I'd set the NewStatus field to be computed to itself when I was messing about trying to get it to work.

It's working lovely again now.     Many thanks again.

Out of interest, how does the clever sublut line worlk?

It looks backwards to me. i.e. if doc being submitted, submit doc.
0
 

Author Comment

by:IanWood
Comment Utility
Clever submit line, even.  
0
 
LVL 22

Expert Comment

by:Bill-Hanson
Comment Utility
The onXXX event handlers are only called when the user initiates the action, not a script.  There is a lot of debate about whether this is the way it should work, but it does work that way by design.

On a positive note, having it work this way gives the developer the flexibility to decide whether the onSubmit code gets  called at all.

Another workaround is to click the button via JavaScript like this:

document.forms[0].submit_button.click();

This will cause the onSubmit to fire.  So you could change your button code to this:

document.forms[0].NewStatus.value = "02";
document.forms[0].submit_button.click();
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In Part 1 (http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_7849-Hex-Maze.html) we covered the hexagonal maze basics -- how the cells are represented in a JavaScript array and how the maze is displayed.  In this part, we'…
Article by: Rob
Notes 8.5 Archiving Steps and Tips This article covers setting up a Notes archive, and helps understand some of the menu choices making setting up and maintaining a Notes archive file easier.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now