API
@-Formulas
JavaScript
LotusScript
Reg Exp
Web Design
Notes Client
XPages
 
Communicating Between XPage and Dialog Box
I was working on an XPage the other day that had a ViewPanel inside with a check box column and I wanted to be able to "bulk edit" multiple fields on the selected documents. I created a dialog box to pop up where you could enter the data that would be updated in all the selected documents. But I discovered that you can't communicate back and forth between the XPage and the Dialog Box natively. This describes how to do that.

First, you need a Java Bean to communicate. That is created under Code | Java. Put the Bean into a package of your choosing (like com.breakingpar.Beans) and define the methods you will need. Here's what I came up with for my Bean:

package com.breakingpar.Beans;

import java.io.Serializable;
import java.util.HashMap;

public class ActionNeededBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private HashMap<String, Boolean> _selectedIds = new HashMap<String, Boolean>();

    public ActionNeededBean() {
    }

    public void clearIds() {
        _selectedIds = new HashMap<String, Boolean>();
    }

    public void setChecked(final String noteId) {
        if (null != noteId) {
            if (!_selectedIds.containsKey(noteId)) {
                _selectedIds.put(noteId, true);
            } else {
                _selectedIds.remove(noteId);
            }
        }
    }

    public Object[] getCheckedIds() {
        if (null != _selectedIds && !_selectedIds.isEmpty()) {
            return _selectedIds.keySet().toArray();
        }
        return null;
    }

    public boolean isChecked(final String noteId) {
        if (null != _selectedIds && !_selectedIds.isEmpty()) {
            return _selectedIds.containsKey(noteId);
        }
        return false;
    }
   
    public int getCheckedCount() {
        Object[] temp = getCheckedIds();
        if (null == temp) return 0; else return temp.length;
    }
}

Now that the Bean is created, you need to tell your application about the Bean. Go to Package Explorer (because this isn't available in the regular Domino Designer interface) then go to WebContent, then WEB-INF, then double-click on faces-config.xml to open that file.

Add the information about the Bean to that file. For example:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
  <!--AUTOGEN-START-BUILDER: Automatically generated by HCL Domino Designer. Do not modify.-->
  <!--AUTOGEN-END-BUILDER: End of automatically generated section-->
  <managed-bean>
      <managed-bean-name>ActionNeededBean</managed-bean-name>
      <managed-bean-class>com.breakingpar.Beans.ActionNeededBean</managed-bean-class>
      <managed-bean-scope>view</managed-bean-scope>
  </managed-bean>
</faces-config>

Being in the "view" scope allows the Bean to communicate fully on a page - it's not needed from one page to another, so a greater scope isn't needed.

Now, on the XPage itself, add in the button code:

<xp:button id="button2" value="Bulk Edit Selected" save="true" style="cursor:pointer;">
    <xp:eventHandler event="onclick" submit="false" refreshMode="partial">
        <xp:this.script>
            <![CDATA[var inputElems = document.getElementsByTagName("input");
var count = 0;
for (var i=0; i<inputElems.length; i++) {
    if (inputElems[i].type === "checkbox" && inputElems[i].checked === true) {
        count++;
    }
}
if(count == 0) {
    alert("No document selected. Please select at least one document to perform this action.");
    event.preventDefault();
}]]></xp:this.script>
        <xp:this.action><![CDATA[#{javascript:
var docIDs = getComponent("viewPanel1").getSelectedIds();
ActionNeededBean.clearIds();
for (var i=0; i<docIDs.length; i++) {
    ActionNeededBean.setChecked(docIDs[i]);
}
if (docIDs.length > 0) {
    getComponent("dlgBulkEdit").show();
}
}]]></xp:this.action>
    </xp:eventHandler>
</xp:button>

The button has client-side code that looks for all the check box elements. If none are checked, then the alert box is given ("No document selected") and the "preventDefault" is called to stop the back-end code from running.

On the back-end code, the ViewPanel is accessed via its ID and the selected items are retrieved and placed into the Bean. Then the dialog box is shown.

The code for the dialog box is only partially shown here, but will give you an idea of the dialog box frame and how to communicate back.

<xe:dialog id="dlgBulkEdit" title="Bulk Editing Documents" preventCache="true" refreshOnShow="true">
    <xp:text escape="true" id="computedField3" style="font-size:12pt;color:#436EEE;font-weight:bold;text-align:center">
        <xp:this.value><![CDATA[#{javascript:var msg = "Only fill out the field(s) you wish to update on the ";
var docIDs = ActionNeededBean.getCheckedIds();
msg += (docIDs.length);
msg += " selected record";
if (docIDs.length > 1) msg += "s";
msg += ".";
return msg;}]]></xp:this.value>
    </xp:text>
    <xp:button value="Cancel" id="button4">
        <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
            <xp:this.action><![CDATA[#{javascript:getComponent("dlgBulkEdit").hide();}]]></xp:this.action>
        </xp:eventHandler>
    </xp:button>
</xe:dialog>

In the dialog box, there is a computed text field that communicates with the Bean and gets the checked ID's. When updating, I loop through the checked ID's and apply updates. The other thing to show in the example here is the "Cancel" button that hides the dialog box. The rest of the dialog box are just labels and fields that are used to gather the input. The "Save" button updates all the selected documents and then hides the dialog box. That code is not shown here, but is very straightforward.