Using the Notes address pickerFor a recent application, I wanted to use the Notes address picker like you see in the mail file (see figure 1). Yes, I know I could have used an editable readers/authors field with "Use address dialog for choices" enabled, but I wanted to force users to pick the names from an address book. With an editable readers/authors field, users can type in names (the field is editable, after all). There are things you can do to validate the names, but I felt (for this application) that forcing the pick from an address book would be the best option. The fields were access fields, so I had to make sure that the format was correct so the people would be granted access. @Picklist([Name]) would be an option, until I realized that users could type in a name inside the dialog box (there's a field called "Add name not in list" when you use a picklist). What did I do?
I decided to play around a little bit with @Command([MailAddress]). I found out (by looking at the mail template) that there's undocumented additional parameters which are optional to the function. Anywhere from one to three additional parameters can be included. The parameters are strings, and are the names of the fields that are to be used for the To, CC, and BCC source, in that order. So this means that I could use the address picker and specify the field name to be used as the source. I didn't have to name my field SendTo just to get it to work. (That was good, because I had two different fields - one for readers and one for authors - and I wanted distinct address pickers for the two fields).
The other requirement I had was to make sure there was at least one name in the reader field. This is because there was already a computed readers field which included an application support role (it's a good idea when you're using reader fields to always include a "back door" role so you can see the documents in an emergency). Since there was already a reader field, then the document would be secured to only people in one or more reader fields. So I wanted to make sure that the user picked at least one person for the reader field.
Obviously, I could use input validation for making sure that there was at least one person in the reader field. And I have that in my application. But I also wanted to "trap" people. If they clicked on the button to update the reader names, I didn't want them to leave without clicking Cancel or picking at least one name. They couldn't click OK with no names listed.
To implement this different interface, I used a couple of fields and a button:
Field 1 - TempAddressPicker - it's a hidden names field that allows multiple values.
Field 2 - ReaderList - it's a hidden readers field that allows multiple values.
Button - Update Read Access - hidden during reading (shown only for editing) - formula to follow.
The temporary field is used to know whether the user clicked Cancel or not. I found there was no way to determine if the user clicked OK or Cancel in the mail address dialog box in formula language. If the user does click Cancel, then all their changes are reverted back to the starting point. So we can compare the updated value to the starting point and see if the user clicked Cancel. (Technically, if the user clicks OK without making any changes, it looks like they clicked Cancel, but that's fine for my purposes).
Here's the button code:
FIELD TempAddressPicker := ReaderList;
FIELD ReaderList := ReaderList;
@If(@Elements(TempAddressPicker) = @Elements(ReaderList) & @Implode(@Text(@Compare(TempAddressPicker; ReaderList)); "") = @Repeat("0"; @Elements(ReaderList)); @Return(0); 0);
@While(@Elements(TempAddressPicker) = 0;
@Prompt([Ok]; "No Readers"; "You must assign at least one person to be able to read this document.");
@If(@Elements(TempAddressPicker) = @Elements(ReaderList) & @Implode(@Text(@Compare(TempAddressPicker; ReaderList)); "") = @Repeat("0"; @Elements(ReaderList)); @Return(0); 0)
The function first makes a copy of the ReaderList field into the temporary field. The second line gets a handle to the field so @SetField (later on) will work. (Technically, I don't know if that's necessary any more in 6 or not, but I've been writing functions since Notes 3, so that's a habit of mine). The next statement brings up the address dialog, using the TempAddressPicker field as the only choice (the "To" in the dialog box). Note that the results are stored back in TempAddressPicker. If the user didn't make any changes and clicked "OK", or if the user clicked "Cancel" (see explanation above) then there will be the same number of elements as what we started with, and the list values will be identical. If you haven't used @Compare before, you should look into it. The function compares two lists and returns a list of numbers. Each number is a comparison of the same-positioned elements in the source lists. If the value is 0, then the two elements are identical. If the values are different, then a +1 or -1 will be returned. So I check to see if the result is an array of number zeros. If there are the same number of elements and the lists are identical, the script quits.
Starting with the @While statement, the code checks to see if the user did not pick anything and clicked OK (if they clicked OK when the list was empty). If they did, then give them a message, reset the TempAddressPicker field back to the way it was at the start (instead of the empty value it is now) and bring up the address picker again. Again, check to see if the user clicked Cancel and exit if they did.
When they finally get out of the @While loop by picking one or more people, set the original field ReaderList to the value the user selected, and then refresh the document. The reason for the refresh is because I have some computed text to show the contents of the ReaderList field to the user.
Like I said earlier, I could have used an editable Readers field or @Picklist([Name]) to get the names, but both of those options had drawbacks that I didn't like. This solution seems to work pretty well for my situation.