Developing traditional Domino Web pages, I often used a symple techinque to dynamically change options in a combobox, depending on a key typed in an input box. Through an Ajax call to a Lotus Script agent, I could use HTML code sent back to the browser by the "print" statement to populate my "<select>" options.
Applying the same technique to XPages it's maybe possible, but it looked to me quite tricky and not consistent with the XPages model. Thus, I started playing with events and Server Side JavaScript to find out a different solution.
A combo box in a web page shows by default a list of options from a Notes View.
Typing a word or a sentence into the input box, a user can refine the search and get a subset of the original list shown in the combobox.
What I needed was not Type Ahead. A user must be able to type a word or a sentence and have the system automatically look for documents containing such a word anywhere in a couple of fields.
The value list for any combobox can be computed using several different languages, including the new Server Side JavaScript. The option "Compute Dynamically" let the code being computed when the web page (or just the element) is refreshed in the browser. Start using Server Side JavaScript is quite tricky, for us used to work with traditional Domino languages and some JavaScript to give some life to our web pages.
I found start using this new technique a little bit confusing, due to its syntax and the fact you can mix toghether code from different languages (Notes Formula, "true" JavaScript, new object and classes). And, last but not least, the lack of details in the official Lotus documentation. Anyway, after a few efforts, and some headache, I found a way to successfully start using this new powerful feature.
As far as I know, you can write your code as it would be a server agent called by an Ajax call, more or less.
In this example, the "on blur" event for the input box and/or the "on click" event for the button store the text typed in the inputbox in a "global" variable, and perform a partial refresh of the web page; thus launching an Ajax call to the server, using the code written in the "Value Formula" of our combobox.
The code seems to be quite efficient; it has been tested in Firefox 3.5, Opera 10, Safari and Explorer 8, against a view containing about 5.000 documents. Refining the choice list always took less than a second.
1. create a new, indexed Database. If the database is not full text indexed, the code will not work
2. create a Notes form "Location". Add 4 text fields: "Name","City","State","CodePV"
3. create a Notes View "(Locations)". Write @SELECT Form="Location" as the Selection Formula. Then add 4 columns: "Name","City","State","CodePV"; the first one indexed.
4. create a Notes View "(FullLocations)". Here, you need just one column using the following formula: Name + " - city: " + City + " - state: " + State
Same selection formula as above.
5. Save several documents using the form you have just created. Fill in all fields for any saved document.
Those are just the elements you need to have the example working. Now, we'll start working on the XPages based code.
6. create a new custom control. Add to it an inputbox, a button and a combobox (call it "comboBox1")
7. select the inputbox, go to "Data" tab, select "Advanced" under "bind data using". In the Advanced box select Use=Scoped Variable, Parameter=Request scope,Variable name=nameToSearch, Compute dinamically.
8. Go to the Events tab, select the "on blur" event and add a Simple Action (Server)
9. In the dialog box, choose Category=Basic, Action=Execute script, Language=JavaScript (Server side)
10. Type a single line of code: sessionScope.nameToSearch=requestScope.nameToSearch
11. Then, go to the "Server Options" box and choose "Partial update". Hit the button "Select element..." and choose the "comboBox1" element.
12. Select the button, Label it "Search", and and add to it the same Action and Server Options as above.
13 Select the combobox element, go to the "Values" panel and hit "Add Formula item..."
14. Choose Language=JavaScript (Server Side), Condition=Compute dynamically, and add following code:
1. var criteria = sessionScope.nameToSearch;
2. var searchKey = "([Name] CONTAINS "+criteria+" OR [City] CONTAINS "+criteria+" OR [CodePV] CONTAINS "+criteria+")";
3. var currDoc:NotesDocument;
4. var myOpt=new Array();
5. if (null != criteria && criteria != ""){
6. var currDb:NotesDatabase = session.getCurrentDatabase();
7. var currView:NotesView = currDb.getView("(Locations)");
8. var viewElem = currView.FTSearch(searchKey);
9. if (viewElem >=1) {
10. for (i=1;i<=viewElem;i++) {
11. currDoc = currView.getNthDocument(i);
12. if (null != currDoc) {
13.
myOpt[i-1]=currDoc.getItemValueString("Name")+" - city:
"+currDoc.getItemValueString("City")+" - state:
"+currDoc.getItemValueString("State");
14. }
15. }
16. myOpt.sort();
17. }
18. else {
19. myOpt = "";
20. }
21. }
22. else {
23. myOpt = @DbColumn(@DbName(),"(FullLocations)",1);
24. myOpt.splice(0,0,"");
25. }
Lines 1-2 grab the text typed in the inputbox (stored in a sessionScope variable, see points 10 and 12 above) and build a string we will use later to perform the search.
For details on the search key syntax, look at the Domino 8 infocenter (http://publib.boulder.ibm.com/infocenter/domhelp/v8r0/index.jsp) and search for the "Refining a search query using operators" document.
Lines 6-8 instantiate the current database, and perform a FullText Search against the view "(Location)". Note that Database must be FullText Indexed, otherwise you'll get a runtime error on the web page.
A FullText Search performed on a NotesView returns an integer containing the number of documents in the view, corresponding to the search condition. Then, you can navigate the subset of documents in the view, using normal methods as .getFirstDocument, .getNextDocument, getNthDocument and so on.
Lines 9-20 just build an array scrolling selected documents in the view, and pass it as the choice list for our combobox. Line 16 sorts the array, since the "collection" of documents returned by the FTSearch method is not indexed.
If variable "criteria" is empty, lines 23-24 compute the value formula for our combobox using a traditional @DbColumn command, and adding a trailing empty value.
15. create a new XPage, name it whatever you want. I just called it "test"
16. add the custom control to the XPage
17. open the XPage in a browser and try it