API
@-Formulas
JavaScript
LotusScript
Reg Exp
Web Design
Notes Client
XPages
 
Using XPages Name Picker from External Function
I was working on an application where I wanted to be able to pick a name from the address book and then perform some actions on the selected name. Instead of creating my own interface into the address book, I thought I would use the Name Picker control built into the extension library. But there are a couple of issues with using that control: I wanted to have a button that would open up the name picker dialog box and then do something after one or more names were picked and OK was clicked.

On the XPage itself, I added a hidden field to hold the results of the dialog box. Because I wanted the ability to add multiple names to the dialog box, I set the multiple value separator property:

<xp:inputHidden id="delegates" multipleSeparator=";" multipleTrim="true"></xp:inputHidden>

Next, I added a script block to set a global JavaScript variable to indicate the computed ID of the hidden field:

<xp:scriptBlock type="text/javascript">
     <xp:this.value><![CDATA[var delegateID = "#{id:delegates}";]]></xp:this.value>
</xp:scriptBlock>

Next, I included the name picker.

<xe:namePicker for="delgates" listHeight="30em" listWidth="30em" dialogTitle="Choose delegate(s)">
     <xe:this.dataProvider>
         <xe:this.namePickerAggregator>
             <xe:this.dataProviders>
                 <xe:dominoNABNamePicker addressBookSel="db-name" addressBookDb="names.nsf" nameList="people" valueNameFormat="abbreviated" searchType="ftSearch">
                 </xe:dominoNABNamePicker>
             </xe:this.dataProviders>
         </xe:this.namePickerAggregator>
     </xe:this.dataProvider>
</xe:namePicker>

By default, an icon appears that can be clicked to open up the dialog box. I wanted to run my custom code instead, so I needed to hide the icon through CSS:

.xspPickerLink { display:none; }

I also did some styling on the dialog box itself, which was done through CSS classes ".dijitDialog" and ".dijitDialogTitleBar". The settings aren't really relevant to the overall solution, so I won't list them here. But one thing I'll point out is that the dialog at first was very transparent, so I set the background-color property on .dijitDialog to get things to show up properly.

The rest of the magic happens in JavaScript. You already saw the script block where I set a global variable to the ID of the hidden input field. To make the dialog box appear, my custom JavaScript code has to execute the "click" function on that name picker icon (the one that was hidden via CSS).

function openNamePicker() {
   var pickerLinks = document.getElementsByClassName("xspPickerLink");
   var picker = pickerLinks[0];
   picker.onclick(); // Open up the dialog box
   setTimeout(watchForDialogClose, 5000); // Wait 5 seconds, then check to see if the dialog is still open
}

This code opens up the picker by executing the "onclick" event on the object with the class of "xspPickerLink". Then it waits 5 seconds and runs another JavaScript function to check if the dialog has been closed or is still open. I picked 5 seconds somewhat randomly - if they open up and click cancel right away, it will be a couple seconds before the "watchForDialogClose" to execute, but the fact that they clicked Cancel means that nothing will have been put into the hidden field anyway, so the timing on that next function doesn't need to be immediate. There's almost no way they will be able to pick a name and click OK in less than a few seconds, so the very earliest my code would need to check for an "OK" click was 5 seconds (I guessed).

The "watchForDialogClose" function will check to see if the "dijitDialog" object has been destroyed (clicking OK or Cancel inside the dialog box will do that). If it has been destroyed, then check for a value in the hidden field. If it hasn't been destroyed (the dialog box is still visible) then simply check again in another 2 seconds. I could have done this every 1 second, but I figured 2 seconds wasn't too bad - if the timing works out that they click OK the instant the function has last checked, it will be 2 seconds before this code runs - not a terrible delay. But by all means update it to be more immediate if needed.

function watchForDialogClose() {
   var allDialogs = document.getElementsByClassName("dijitDialog");
   var dialog = allDialogs[0];
   if (dialog) { // dialog box is still open, check again in 2 seconds
      setTimeout(watchForDialogClose, 2000);
   } else { // Dialog box is closed
      var inputField = document.getElementById(delegatesID);
      if (inputField.value != "") { // Name was picked and OK was clicked
         // The code I execute isn't relevant to this tip, but it submits a form to the server for processing.
      }
   }
}

That's it. Custom code that opens the built-in name picker and watches for the name picker to be closed.