Populating List Boxes

When I occasionally browse around some of the LiveCycle forums, I frequently see questions around how to populate a drop down list.  I have put together a sample form that illustrates several different options.

Data Source

There are two basic sources for updating a drop down list definition: data binding or script.  If the list contents are defined as part of your form data, and if they don’t change during your form session, then use data binding.  If the definitions are more fluid, then use script.

The preOpen Event

The most important take-away from this blog entry concerns what event to use for updating lists.  I have seen customer forms that update list contents using change, exit, calculate, validate, mouseover, and enter events.  However, the proper place to do it is in the preOpen event.  The preOpen event fires when the user activates the control for the choice list.  Think of it as the "just-in-time" option.  If you try to maintain your list box definition from other events then often your script will update your list box contents too frequently. 

The only reason for updating a choice list sooner than the preOpen event is if you need to assign a value to a list field.  e.g. if your drop down list has a display value: "ONE" and a bound value: "1", then assigning
field.rawValue = 1; will cause the field to display "ONE".  Obviously this works only if the field has up to date list contents.  If you need your list contents updated more frequently, you should still put the list populating logic in the preOpen event, and use execEvent("preOpen") to populate the list from other contexts where it’s needed.

The sample form has four choice lists that get populated from their preOpen event, using data found in form field values, JavaScript arrays and XML data.

Script Commands

There are two script methods for setting your list box contents:
field.addItem()
   and
field.setItems()

The API: field.addItem() works in all versions of Reader.  field.setItems() was introduced in Reader 9.0 and is much faster and more convenient.  The sample form has script that illustrates how to use each method.

Binding to Data

I constructed some sample data (dogs.xml) that looks like this:

<dogs>
  <category file="ugliest">
    <rank>1</rank><dog>Chinese Crested</dog>
    <rank>2</rank><dog>Pug</dog>
    <rank>3</rank><dog>Shih Tzu</dog>
    <rank>4</rank><dog>Standard Schnauzer</dog>
    <rank>5</rank><dog>Chinese Shar Pei</dog>
    <rank>6</rank><dog>Whippet</dog>
    <rank>7</rank><dog>Dandie Dinmont Terrier</dog>
    <rank>8</rank><dog>Japanese Chin</dog>
    <rank>9</rank><dog>French Bulldog</dog>
    <rank>10</rank><dog>Chihuahuas</dog>
  </category>
  <category file="dumbest">
   …
  </category>
  <category file="comicBook">
   …
  </category>
  <category file="smartest">
   …
  </category>
</dogs>

On my form I want two drop down lists: one with the names of the categories and a second that gets populated with the contents of the category.  Since this XML is part of my data, I bound the category using these expressions:

binding

The second list has a preOpen event that locates the category in the data, and then populates a second listbox from the category contents:

// Find the data group that corresponds to the category chosen
// in the Category field

var vDogs = xfa.datasets.data.dogs.category.all;
var vChoice = null;
var i;
for (i = 0; i < vDogs.length; i++) {
    if (vDogs.item(i).file.value === Category.rawValue) {
        vChoice = vDogs.item(i);
        break;
    }
}
if (vChoice !== null) {
    // vChoice.dog.all is the equivalent of the
    //
SOM expression: "category.dog[*]"
    var vDisplayValues = vChoice.dog.all;
    var vBindValues = vChoice.rank.all;
    for (i = 0; i < vDisplayValues.length; i++) {
        this.addItem(vDisplayValues.item(i).value,
                    
vBindValues.item(i).value);   
    }
}

Performance

Populating a list from data is very efficient.  But populating large lists or many lists using addItem() can be slow.

The performance gains of setItems() over addItem() is substantial.  If your form makes extensive use of choice lists or has choice lists with large contents, you will appreciate the improvements of setItems().  Of course, this option is available only in forms designed for Reader 9 or later.

Web Services

In some cases, the definition of the choice list may be held on a server.  In this scenario, the best strategy is to add a WSDL connection to your form that retrieves the list contents.  Have your list box bind its contents to the data retrieved via the SOAP call.

Away for a week

After I eat lots of turkey on the weekend (Canadian Thanksgiving), I’m spending next week trying to empty the job jar at home.

12 Responses to Populating List Boxes

  1. Jeff K says:

    Great Post!I was hoping in the future, you could dive more into the WSDL connection and show an example of the WSDL. Every time I try using a WSDL on one of my FORMS, I can never get the drop down box to work. I only seem to retrieve the first value, not my whole list.

  2. Jeff:That’s a good suggestion. Do you know of a public domain web service that I could call from a sample form? If I had one of those, I could deliver a working sample.John

  3. Jeff K says:

    John:In the past, for testing I have used http://www.webservicex.net.There is a Currency Convetor that works well. Like http://www.webservicex.net?CurrencyConvertor.asmx?WSDL (I found this from the book PDF Forms Bible by Padova Okamoto)I could get this one to work on my form, but have not been able to create a working custom one yet.Hope this helps.

  4. DSP says:

    Is there anyway that when you pick Dog Category “smartest” that the Populated by scripting to the XML choices gets prefilled with the first record or maybe the default pick of “Chinese Crested”? But then users can still change the pick using the drop down list.

  5. Good question.I’ve updated the sample to do what you’re looking for.I moved the logic from the Category change event to the exit event and changed it to:Choices.clearItems();Choices.execEvent(“preOpen”);Choices.selectedIndex = 0;The selectedIndex property chooses which entry to display — based on position in the list.I also enhanced the preOpen event so that it doesn’t re-populate the list if the Category has not changed.(Prior to this ‘enhancement’ there was a bug in my script where I’d append entries to the list on each preOpen — rather than clearing the list first…)John

  6. Jeff:There you go… A new blog entry that hopefully does what you want:http://blogs.adobe.com/formfeed/2009/10/populate_a_listbox_from_a_web.htmlJohn

  7. Joanne says:

    John, I’ve been trying to figure out how to do this for weeks (the pulling of the XML data as you have done in the dogs section). I have saved both your dogs.xml file and your ListBoxes.pdf file in a folder together. When I open ListBoxes.pdf in LiveCycle and go to the Preview tab, it works great. However, when I double-click on ListBoxes.pdf and just bring it up in Adobe Professional, the dropdowns for “Dogs Category” and “Choices” do not work. I’m working with the original files downloaded on this page so I haven’t changed anything. Do you know what the problem might be? I feel like I’m SO close (finally) to figuring this out…if I can get this to work. Thanks!

  8. John Brinkman says:

    Joanne:
    The problem is that dogs.xml (the form data) was not embedded in the PDF.
    It gets embedded when you preview, but not when you save.
    You fix it by opening the form in Acrobat and importing form data.
    I’ve also updated the sample pdf so that it has the data embedded.

    John

  9. Joanne says:

    Ok, I see. Thank you…that works! My situation is that I have about 120 forms that I need to import data from. John, is there any way to tell the form to automatically import the form data? My users would never know how or remember to do that on each form that we use.

  10. Joanne says:

    …by the way, they will all be using Adobe Reader…that may make a difference in your reply. Thanks!

    • Joanne:
      Is the data changing? Does it need to be re-imported? Once you follow the steps where you import the data (in Acrobat) and save, the data is preserved in the PDF and does not need to be re-imported. The PDF can then be opened in Reader.
      If the data you are using changes regularly and needs to be re-imported at form open time, you could consider getting the data from a web service. See: http://blogs.adobe.com/formfeed/2009/10/populate_a_listbox_from_a_web.html
      However, if you use a web service, you the form needs to be rights-enabled in order to be used in Reader.
      John

      • Joanne says:

        Thank you John. Yes, the data will change, but only occasionally. It sounds like I need to either simply re-import the data into each form when there is a change (time consuming but less so than changing each list within the form), or use the web service. The latter would work better…if I can figure it out! :)
        Thanks so much for all your help!