Have it your way: Combine JavaScript, LotusScript, and Formulas in your web buttons.

A Notes R4.6 and later database property, "Web Access: use JavaScript when generating pages" enables all the Notes active elements on your web form. Active elements include action hotspots, hotspot buttons, action bar buttons, and navigator regions. These elements can execute Simple Actions or Notes Formula language. This is useful because the same active elements that you develop for Notes client access can be executed by web clients. But there is still a limitation in that you cannot natively create one HTML object that executes a combination of JavaScript and a Notes active element with a single click.

    Using this database property also adds some new limitations. For example, you can no longer implement simple front-end field validation in JavaScript before submitting.

    With an understanding of how the "Web Access: Use JavaScript..." property works, this article illustrates some undocumented techniques you can use to take control of Notes button execution combined with JavaScript execution in a "single-click" combination. You can create a single button that combines the pizzazz of JavaScript, the power of Formula language, and the integration potential of LotusScript and the new back-end Java classes for Notes. At http://www.MartinScott.com you can play with these and other examples on-line and download the source code.


    How the "Web access: use JavaScript when generating pages" property works

    With this database property enabled, Domino renders all Notes active elements as HTML buttons and active images. When the web user clicks one of these buttons or images the browser records onto the page which button or image was clicked, then submits the page to the server. When the Domino server receives the submitted page it needs to know which button or image the user clicked. To accomplish this tracking, the Web access: use JavaScript property adds some HTML and JavaScript to the beginning of each edit-mode page. At submission time, Domino monitors what button action was clicked by checking a special, hidden, HTML input named "__Click".

    Consider the simple form in Figure 1. It has one hotspot button and one action bar button.


    Figure 1: WEB FORM DESIGN WITH MULTIPLE BUTTONS--Both the hotspot button and the action bar button will be rendered in HTML.

    Figure 2: FORM PREVIEWED IN WEB BROWSER--Domino R4.6 can depict more than one button.

    Figure 3 reveals the output of the form in Figure 1.

    Figure 3: JAVASCRIPT ADDED BY DOMINO--Domino adds JavaScript to track which button the user clicks.

    In Figure 3, the relevant lines of code are:

    Lines 5-14: Domino generated function to set the __Click field and submit the form.
    Line 20: Hidden __Click HTML input field
    Line 23: Domino's HTML translation of a button labeled "Save and Continue Later" in the action bar of a form
    Line 29: Domino's HTML translation of a button labeled "Register" in the body of a subform

    The HTTP submit action must be supplemented by setting the value of "__Click" to a Notes formula address value. This formula address is comprised of three components, each separated by a /,

    1) The UNID of the form, subform, view, or navigator which contains the button or hotspot.
    2) The Notes design context flag "$Body", "$ACTIONS", or "$ViewMapLayout" depending on whether the button is in a form body, form or view action pane, or navigator.
    3) The Notes item identifier for the button on that form.

    Together, the Notes formula address might look like

    66ce0207b3b26ec0852565ba005a4597/$Body/0.10

    In Figure 3, notice that the UNID of the subform-based Register button from Figure 1 is different than the UNID of the Save and Continue Later button, which is stored on the form.

    Some other interesting things to know about this new database property are

    _ Domino only saves the document to disk during an HTTP submit if the clicked button formula contains @Command([FileSave]).
    _ Domino handles the click tracking a little differently for documents in read mode, but it does not affect the techniques here.
    _ The form UNID does not have to be the same form Domino is rendering. It can be any form, subform, view, or navigator in the database.
    _ The item identifier in the Notes formula address is always "0.10" for the first object in the body of a form.

    These last two observations will prove useful in Example 1, below.


    Combining JavaScript with Notes actions

    This article includes several techniques for combining JavaScript with Formula language, LotusScript, and Java. The techniques you will want to consider for your applications will depend on whether you want to execute the JavaScript first, or the Notes action first. Therefore, these example techniques are organized by JavaScript execution sequence.

    Some of these examples use the new database property Web pages: use JavaScript. Some examples do not use this feature, although they are included here because they solve the same class of development problem: combining JavaScript and Notes actions into a single button.


    Example 1. JavaScript followed by a Notes formula

    Suppose you want your user to click a Save button, which first checks to see if the user has entered data into a particular field. If the field is blank, JavaScript pops up a message reminding them to fill-in that field.

    This was fairly straightforward in the simple button behavior of Domino 4.5. However, if you want to render multiple buttons using the Web access: use JavaScript property, you’ll find that a regular HTML submit action does not actually save the document. This is due to the fact that, when this database property is enabled, Domino R4.6 will only save the document to disk when the user has clicked on an active element that includes an @Command([FileSave]). Therefore, you have to leverage your knowledge of how this new R4.6 database property works to trick Domino into executing your formula.

    To cause your button formulas to execute, this technique first runs a custom JavaScript routine, then submits the page by passing to the _doClick() function the Notes address for the formula that Domino should execute. Finally Domino executes that formula and returns the user to the resulting document.

    Here are the step by step instructions for implementing this technique.

    1. Create a new form called ButtonSave. This form will be used only to store the button created in Step 2.
    2. Create a button in the upper left corner containing the code that you want to execute. For example,

    @Command([FileSave]);
    @Command([FileCloseWindow])


    Figure 4: BUTTONSAVE FORM--Each button formula is stored on a dedicated form.
    This keeps the Notes formula address predictable and consistent, regardless of where we place the button.

    3. On your web form (different from the form in Step 1) place the following JavaScript and HTML as pass-thru HTML

    <INPUT type="button" value="Register" onClick="javascript:Save();">
    <SCRIPT language="JavaScript">
    function Save() {
    if (document.forms[0].EmailAddress.value != "") {
    // call the _doClick function with the address of the Register button
    // obtained by previewing the ButtonRegister form in a browser
    _doClick('[--PUT FORMULA ADDRESS HERE--]');
    } else {
    alert('Please enter your Email Address.');
    }
    }
    </SCRIPT>


    4. Return to the ButtonSave form (not the web form in Step 3) and choose Actions...Preview in Web Browser. Then use your browser's feature to view the Page Source. Look for the HTML rendition of the button. Hotspots will begin with the format

    <A HREF="javascript:_doClick('66ce0207b3b26ec0852565ba005a4597/$Body/0.10')

    and buttons will start with the format

    <INPUT TYPE=button onClick="_doClick('66ce0207b3b26ec0852565ba005a4597/$Body/0.10')

    Copy to the clipboard the Notes formula address. This is the portion of the _doClick function call that lies between the single quotes.

    6. Paste the Notes formula address (copied from Step 4) in between the single quotes of your JavaScript _doClick function call in Step 3, in place of the [--PUT FORMULA ADDRESS HERE--].

    7. Re-mark the entire JavaScript and HTML areas as Pass-thru HTML, since text pasted from outside Notes is, by default, not marked as pass-thru HTML.


    Figure 5: FRONT-END FIELD VALIDATION IN JAVASCRIPT--
    The Input button named Register triggers the custom JavaScript validation routine.
    The HTML button can be moved anywhere on the form without
    affecting the Notes formula address of the button in Figure 4.

    8. Preview the web form in your web browser.


    Figure 6: WEB OUTPUT--JavaScript validation is possible, even with the database property
    'Web access: use JavaScript when generating pages' enabled.

    Notice that JavaScript first validates your entry in the EmailAddress field, then calls the Notes formula in the ButtonSave form to perform the save to disk. This example is very simple, but you could add any other JavaScript in the Save() function. You could also make the ButtonSave Notes formula much more complex.

    One important point to understand is why you should place the button on its own form. This allows you to change where the HTML button occurs on your web form without changing the critical Notes formula address of the button in Figure 4. If the Notes button were stored on your web form, its formula address would change whenever you change the position of that button on the web form. By giving each button its own form, you can move the HTML button tag all you like without worrying that the formula address will change. In fact, to further modularize the button implementation, you may wish to use a shared field in your JavaScript, instead of hardcoding the Notes formula address. Then you only have to update that shared field once, while you use the same button on several forms.

    This technique can be used for many other powerful features, such as refreshing fields automatically when the value of an HTML Select drop down keyword field changes.

    Caveats
    In this technique, forms that are manually copied from one database to another get their UNID reassigned, and therefore your Notes formula addresses for buttons on such forms must be manually changed in any JavaScript calls. Forms that are deployed using an OS-level file copy, database-level copy, replication, and design refresh/replace do not change their UNID and therefore do not need updating.

    It is possible to dynamically determine the UNID of a form from the form name as a page is being served, but it requires a LotusScript call to a Notes API function and may significantly reduce performance.

    Example 2. Notes formula followed by JavaScript

    Suppose you want your user to click a button which immediately executes a @DbLookup formula and displays some output in a JavaScript pop-up alert window. In this technique, Notes writes the output of a multi-line formula to a place on the form which, when returned to the browser, constitutes some data or instruction in a JavaScript routine. This technique requires R4.6 and the database property..."Web access: use JavaScript when generating pages" enabled.

    1. On your form, place the following

    <SCRIPT language="JavaScript">
    message = [--NOTESFIELD--] ;
    if (message != "") {
    alert(message);
    }
    </SCRIPT>

    2. In place of the [--NOTESFIELD--], put a Notes computed field named PopUpMessage, with a formula

    PopUpMessage

    3. Create a Notes button containing your code. At the end of your formula, include a statement that writes your message to the PopUpMessage field, such as

    FIELD PopUpMessage := PopUpMessage;

    Exists := !@IsError(@DbLookup("":"NoCache"; "":""; "Entries"; EmailAddress; 1));

    @If(Exists;
    @SetField("PopUpMessage"; "The email address " + EmailAddress + " has already been registered! You can only register each email address one time.");
    @Do(@Command([FileSave]);
    @Command([FileCloseWindow]))
    )
    Note that the formula in step 3 assumes that you have a view named Entries with first column sorted on EmailAddress.


    Figure 7: NOTES FORMULA FOLLOWED BY JAVASCRIPT--The Register button writes output to the PopUpMessage field, which feeds a JavaScript pop up alert routine when the form is served back to the user.

    4. You can now preview the web form in your web browser and test it out.

    When you enter a value into the field and click the Register button, Notes executes the Register button formula. This formula writes a message to a field that Notes subsequently displays as an expression in the JavaScript code. If the user enters an EmailAddress that is already in the view the user is alerted, and the document is not saved.

    Figure 8: WEB OUTPUT--Robust data validation against existing records, combined with friendly pop up alerts.


    Caveats
    In this technique, the JavaScript action will execute again if the user reloads the page. If this behavior is not desired, it can be worked around by first checking the value of a hidden HTML field before executing the javascript action. Then the JavaScript code would have to set this hidden HTML field after execution.



    Example 3: JavaScript followed by LotusScript

    Suppose you want to create a button that executes a LotusScript agent on the current page, but only after getting a confirmation from the user. In this technique JavaScript handles the confirmation, then executes a back-end Notes Agent via URL. In the URL, JavaScript passes to the agent the Universal ID (UNID) of the document to be processed. The agent uses this UNID to get and process the document, and then redirects the user back to the document to see the result. This technique requires R4.5+, and does not require the database property "Web Access: Use JavaScript when generating pages".

    1. Create an HTML button by adding this pass-thru HTML code to your form

    <form><INPUT type="button" value="Run Agent" onClick="javascript:runAgent();"></form>

    <SCRIPT language="JavaScript">
    function runAgent() {
    // Here, place any JavaScript you'd like to run before executing the agent
    if (confirm('Click OK to process this document.')) {
    self.location.href='/[--NOTESFIELD_1--]/myAgent?OpenAgent&[--NOTESFIELD_2--]';
    }
    }
    </SCRIPT>

    2. Place on the form a Notes computed for display field named Message, with a formula

    Message

    3. In place of the [--NOTESFIELD_1--], put a Notes computed for display field named dbName, with a formula

    @Subset(@DbName; -1)

    4. In place of the [--NOTESFIELD_2--], put a Notes computed for display text field named ThisDocUNID, with a formula

    @Text(@DocumentUniqueID)


    Figure 9: JAVASCRIPT FOLLOWED BY LOTUSSCRIPT--
    The Run Agent HTML button executes JavaScript first, then triggers a Notes agent via URL.

    5. Create an agent named myAgent

    6. Set Which document(s) should it act on to 'Run once (@Commands may be used)'

    7. Enter the following LotusScript code:

    Sub Initialize
    Dim s As New NotesSession
    Dim thisDB As NotesDatabase
    Dim thisDoc As NotesDocument
    Set thisDb = s.currentDatabase

    '...From the URL, get the UNID of the current document and use it to get a handle to the doc
    thisDocId = Right$(s.DocumentContext.QUERY_STRING(0), 32)
    Set thisDoc = thisDB.GetDocumentByUNID( thisDocId )

    '...process the document
    thisDoc.Message = "LotusScript wrote this"
    '...
    '...update the document and return the user to it in edit mode
    Call thisDoc.save(True, True)
    redirect$ = "[" & thisDB.FileName & "/$defaultView/" & thisDoc.UniversalID & "?editDocument]"
    Print redirect$ '...redirect the user
    End Sub

    7. Save the agent. Then preview the web form in your web browser and test it out. I added an editable field and a Save button to easily allow me to save the new document to disk, a necessary step before LotusScript can act on the document.


    Figure 10: WEB OUTPUT--JavaScript can trigger a Notes agent,
    which can write output to the current document and represent the document back to the user.

    On the form, you could add your own front-end preprocessing of the form data in JavaScript. On the agent, you could add any LotusScript or Java code to the agent, allowing you to integrate with other database systems or perform complex iterative processing.


    Example 4: LotusScript followed by JavaScript

    In this example, imagine you want a web button that pops up an alert window displaying the size of the current database. First, this button will call a LotusScript agent via URL. The agent will do some processing and return a stream of HTML to the browser. This HTML will include JavaScript code to alert the user with the output from the LotusScript agent. This technique requires R4.5+, and does not require the database property "Web Access: Use JavaScript when generating pages".

    1. Create an HTML button by adding this pass-thru HTML code to your form:

    <form><INPUT type="button" value="Check Size of this database" onClick="location.href='/[--NOTESFIELD--]/CheckSize?OpenAgent'"></form>

    2. In place of the [--NOTESFIELD--], put a Notes computed for display field named dbName, with a formula:

    @Subset(@DbName; -1)

    3. Create an agent named CheckSize

    4. Set Which document(s) should it act on to 'Run once (@Commands may be used)'

    5. Enter the following LotusScript code

    Sub Initialize
    Dim s As New NotesSession
    Dim thisDB As NotesDatabase
    Set thisDb = s.currentDatabase

    messageText$ = "This database is " & thisDb.Size & " bytes."
    PopUpMessage$ = |<SCRIPT language="JavaScript">| &_
    | alert("| & messageText$ & |"); | &_
    | location.href="./" | &_
    | </SCRIPT> |

    Print PopUpMessage$ '...send the javascript to the user
    End Sub

    6. Save the agent, then Preview the web form in your web browser and test it out.


    Figure 11: WEB OUTPUT--LotusScript can write data back to a JavaScript routine,
    bringing back end Notes integration functionality to the front-end form.

    Here, as in the previous example, you could add any LotusScript or Java code to the agent, allowing you to integrate with other database systems or perform complex iterative processing. In the agent, you can embed more complex JavaScript code, although editing the code is a little messy since it's embedded in LotusScript. Some useful examples of more complex JavaScript might include the JavaScript window.open method to create functionality similar to @DialogBox.


    Conclusion

    These examples show several techniques for mixing JavaScript with Notes formulas and LotusScript. A natural extension of these concepts would be to chain several of these techniques together. For example, you could have a form that validates the user’s input with JavaScript, then triggers a complex formula to search for duplicate entries already in the database, and finally delivers a pop-up message via JavaScript if it finds any duplicates.

    The Notes 4.6 database property "Web access: use JavaScript when generating pages" offers some nice conveniences when developing button-rich forms, views, and navigators to be used in Notes and on the web. By understanding how this functionality works behind the scenes, you can build web buttons that leverage the front-end power of JavaScript in conjunction with the powerful built-in features of Notes.

    Acknowledgements
    Thanks to Jim Knight of LavaTech, Inc. (http://www.LavaTech.com) for the concept in Example 2.