There are a number of options for prompting user input using LotusScript. In increasing order of complexity and usefulness, they are:
- The NotesUiWorkspace prompt
- Displaying a custom dialogbox
First, you can use the good old InputBox function [i.e. userStr =InputBox (prompt, title, default)]. This is pretty basic -- the equivalent of the simplest Formula language @Prompt. I hardly ever use it, except for the most quick-and-dirty non-production applications.
The trouble with InputBox is that it does not take advantage of the last 25 years of user interface advances. If you want, for example, to prompt users for a yes or no answer, you have to give them a kludgy text prompt, such as "Do you feel lucky punk?: (Y/N)" and then manually validate their answers. They will ALWAYS see an "OK" button and a "Cancel" button.
A better solution is to use MessageBox. We all use MessageBox as a statement to display messages to the user, but it offers a number of features to increase its usefulness. For instance, MessageBox can be called as a function to return a value, including one of many enumerated types that can be used to exploit the rich UI available within Lotus Notes.
The many features and options of MessageBox are well documented in Domino Designer Help, and are very easy to use, so I'll just give two quick examples:
Making a statement: %Include "lsconst.lss" MessageBox "Error: Unable to find database." , MB_ICONEXCLAMATION , _ db.title & " – Data Insertion Tool" Asking a yes or no question: %Include "lsconst.lss" If MessageBox("Warning: Action will result in reactor SCRAM. _ Are you sure you want to continue?", _ MB_ICONEXCLAIMATION+MB_YESNO, _ db.title & " - Reactor Control Module")=IDYES then ' SCRAM reactor Else ' abort action End if
Search the index view of Domino Designer Help for more information. Be aware that your code needs to contain the line %Include "lsconst.lss" to include the MB and ID constants used above. Lsconst.lss is a text file that is installed with Lotus Notes, and the value of using its constants should be obvious. However, I should point out one caveat: all constants contained in lsconst.lss are declared PUBLIC.
This means that if you reference this file in a script library -- which is itself referenced by code, which in turn references this file -- all the variables will become duplicate references, and you'll wear out your "enter" key getting rid of the warnings when you try to save your code. If you build standard script libraries shared by many applications, this is very likely to happen. This is one of those "gotchas" that causes one to ask whether anyone at IBM Lotus actually develops applications in their own products.
One way around this is to create a copy of lsconst.lss in which you remove all instances of the word "Public" -- but I don't recommend doing that. Another solution is to print out the constants related to MessageBox and stick them on the wall for handy reference.
A better solution is to design your applications so that code running in a library never uses any UI functions. But that is almost impossible without structured error handling, which LotusScript does not support.
The NotesUiWorkspace prompt
If these functions don't give you what you need, you can create an instance of NotesUiWorkspace and use its prompt, pickliststrings and picklistcollection functions.
The first of these duplicates the rest of the @Prompt functionality; the next replaces @Picklist; and the last goes picklist one better by returning a list of documents, just as if they were selected in a view or returned from a database.search.
Again, these are well documented, just look up NotesUiWorkspace in the Domino Designer Help Index. I won't give an example here, because these functions are pretty well documented in Help, and I want to at least touch on the extremely powerful dialogbox method.
Displaying a custom DialogBox
You are probably aware of the @dialogbox Formula language command, and you may even have run across the NotesUIWorkspace.DialogBox method. The documentation unimaginatively makes it sound as if these functions are mainly for displaying a subset of another form -- for example, to present a calculator or summary of the current document to the user.
In fact, when R4 was released, the documentation did not even mention that an optional parameter allowed DialogBox to display a document other than the one currently open for edit. This was most unfortunate, because it made one of the most useful features in the whole product look like an aside.
But DialogBox is far from an aside. Every non-trivial application I have developed since R4 has used at least one DialogBox. DialogBox is the key to providing a rich, robust user experience.
Let's say you want to write an agent that will update any of several fields in one or more selected documents. You could create one agent for each field. But that is, at best, an awful solution. Instead, you can create a form that allows a user to specify multiple values at once. Next you write a single agent that displays this form in a DialogBox, and then applies the specified updates to ALL selected documents. You can even save the values entered into the dialog to a profile document and reload them the nest time the agent is run. The usefulness of this feature is impossible to overstate!
Let's take a slightly more complex example to illustrate how to actually code a DialogBox. Let's say the user is editing a document in a request-tracking database. Under certain circumstances, you would like to present the user with a DialogBox stating that an exception has been found, and asking that they fill in some information and send a request for more information back to the originator of the request.
This information will NOT be stored on the document the user is editing. Rather, it will be written to a log and included in an e-mail. The e-mail will contain a link to the current document. The only information stored in the current document will be a status flag.
We'll ignore the details of creating the form used to format our dialog box, except to state that:
- It will be a form called "Dlg_MoreInfo."
- It will contain all its controls within a table (more on that later).
- The background of the form and the table will be set to the system color.
Now, when the exception is detected within the request document, the following code will be called, perhaps from a button click or the request form's "Postrecalc" or "QuerySave" event:
Dim ws as new notesUIworkspace Dim s as new notesSession Dim db as notesdatsbase Set db= s.currentDatabase Dim TrackingRequest as notesDocument Dim MoreInfoDialog as notesDocument ' so we can get data off document being edited… Set TrackingRequest =ws.currentDocument.document ' create doc to be used by dialog-never to be saved… Set MoreInfoDialog=db.createDocument … initialize value of fields defined on dialog form or needed by it …. MoreInfoDialog.Prompt="Exception found" ' or whatever MoreInfoDialog.reqUNID= TrackingRequest.universalid ' just an example… ' Present dialog If ws.DialogBox("Dlg_MoreInfo",true,true,false,false,false,false, _ db.title,_" MoreInfoDialog" ,true) Then ' If user clicked "Cancel" in Dialog, we would not be here! ' So send request for info back to requestor Dim MoreInfoMemo as notesDocument Set MoreInfoMemo =db.CreateDocument MoreInfoMemo.form="Memo" MoreInfoMemo.Subject="Need more data!" ;…format body based in data entered in dialog… Dim memoBody =new NotesRichTExtItem(MoreInfoMemo,"Body") Call memoBody.AppendText(MoreInfoDialog.WhatsNeeded(0)+"whatever…") Call memoBody.AllendDocLink(TrackingRequest) Call MoreInfoMemo.send(false, TrackingRequest.Requestor(0)) End ifThat's the DialogBox method in a very small nutshell. At first, it looks daunting. But after you do it once or twice, there is nothing to it.
The form used to present the dialog box has all the normal form events that can be used -- for example, for validation. You should be aware that in a DialogBox of this kind, the QuerySave event will NEVER fire (because the document will never be saved).
Indeed, you should include on the MoreInfoDialog form, a computed field called "Saveoptions" set to "0" to prevent this form from being accidentally used to create documents during testing. Also, for this example you should be aware that the appenddoclink call will fail unless the current database has a default view set.
I mentioned above that all the controls on the dialog form are placed within a table. In R4, there was an undocumented feature that helped when using DialogBox. When DialogBox was used with the second and third parameters (which control auto-sizing of the dialog box) set to true, and if the form being used contained a layout region, then ONLY the layout region would appear in the DialogBox.
This made for a neat clean interface, since you normally want tight control over formatting in a DialogBox, and you normally DO NOT want Lotus Notes to decide that the form is too tall and display a scroll bar. On the other hand, layout regions are a pain to layout, and there ware some other quirks I won't go into.
Well in R5, IBM Lotus found a better way. A new tenth parameter (right after the document handle) tells dialogbox to display only the first non-hidden table (if any) on the form. This achieves a similar effect (only without the quirks), and it's MUCH easier to lay out control using a table than a layout region. So always use the table, always set the tenth parameter, and never give it another thought.
Do you have comments on this tip? Let us know.
Related information from SearchDomino.com:
Please let others know how useful this tip is via the rating scale at the end of it. Do you have a useful Lotus Notes, Domino, Workplace or WebSphere tip or code snippet to share? Submit it to our tip contest and you could win a prize.
This was first published in May 2006