Search This Blog

Sunday, 5 May 2013

Drop-Down List Control with auto-complete (Searchable Drop-Down List)

Note:

An updated version of this sample is available in a later blog here.

 

Problem

In the standard drop-down list control that comes with LiveCycle Designer when a user types a character the first item starting with that character is selected. But in other environments it is becoming more common to have full auto-completion, so as the user types matches include the second, third, etc characters.

Solution

This solution uses a textbox as the drop-down list UI component and a list box to display the selected items. This is a cleaner version than one I posted in this forum thread http://forums.adobe.com/thread/518910

Detailed explanation

This example show the selection of a country, so as the user types into the 'Drop-Down List' (actually a textbox) the matching countries are displayed.


This is the code in the change event that updates the items in the list with countries that match the characters typed.

// For each character entered by the user, start by clearing all the current items.Results.CountryList.clearItems();
// If they have cleared the contents of the Search box close the 'Drop-Down List'

if (xfa.event.newText == "")
{
    Results.presence = "hidden";
    Results.CountryList.presence = "hidden";
}
else
{
    var list;
    // Select values to load depending on the matching option selected. We use FormCalc predicates to select the values.
    // The data used in this example has the structure of <country id="AU" name="AUSTRALIA" />
    // So if country matched this element then country.name.value would be "AUSTRALIA", country.id.value would "AU" and
      // country.index would index of AUSTRALIA in the Countries list.
   

    if (this.desc.nodes.namedItem("matchFirstCharacters").value)
    {
        list = xfa.resolveNodes('$record.country.[Lower(Left(name,' + (xfa.event.newText.length) + ')) == "' + xfa.event.newText.toLowerCase() + '"]');
    }
    else
    {
        list = xfa.resolveNodes('$record.country.[At(Lower(name),Lower("'+xfa.event. newText+'")) > 0]');
    }
    // Load the values up    for (var i = 0; i < list.length; i++)
    {
        var country = list.item(i);

        Results.CountryList.addItem(country.name.value, country.index.toString());
    }
    // Make the 'Drop-Down List' visible
    Results.presence = "visible";
    Results.CountryList.presence = "visible";
}

The code has an option to match against the first characters in the list item or any characters in the list item, this is determined by the "matchFirstCharacters" value under the desc element of the Search textbox.  This acts as a custom property of the control and in this sample you can see how it is updated in the change event of the Radio Button List.

This method works best when the 'Drop-Down List' is contained within a positioned subform so that when the list opens it will overflow any content following it, otherwise in a flowed subform the content will be moved down to make room for the list to open.

I did try using a standard Drop-Down List control to acheive this behaviour but was not able to update the items while the Drop-Down List was open.

Download sample Countries.pdf or download the Countries.xdp and Countries.xml.

11 comments:

  1. I'd like to thank you first for posting this version. It's the only thing I've been able to find to accomplish what I need. My question is, if I have my data in the Listbox itself, how would I write the filter script? Where do I point to the items? I'm very new to this and only need to write on form for the new ICD-10 system so I can filter diagnoses. Any help is much appreciated.

    ReplyDelete
  2. Here is a sample that uses a custom dataset. You can add any valid XML under the xfa:datasets elements (just remove any XML declaration). The only problem is that you have to do this in XML Source view. But once this has been done there is very little that needs to be done to the code. Just change xfa.resolveNodes('$record.Country to xfa.datasets.Countries.resolveNodes('Country.

    Have a loot at this updated sample. https://sites.google.com/site/livecycledesignercookbooks/Countries.Custom.DataSet.xdp?attredirects=0&d=1

    An alternative, if you didn't want to use XML Source view, would be to use a hidden Listbox, but that would be a bigger code change.

    Regards

    Bruce

    ReplyDelete
  3. That's fantastic!
    Just another question, I am bypassing the filter feature for now and would like multiple text fields/list boxes so that I can have more than one diagnosis. I've tried duplicating and then renaming and even naming the XML source "Countries2" but the second text field will not work. Only one per form/sheet. Any ideas? You've been my top resource for trying to figure this out!

    ReplyDelete
  4. Hi,

    It should just be a matter of duplicating the DropDownList subform (you can select it and use Ctrl-D). All you should need to change then is the dataset element in the XML source (like you have done to "Countries2") and change the code in change event of DropDownList.Background.Search to point to the new dataset element (in two places), would look like;

    list = xfa.datasets.Countries2.resolveNodes('Country.[Lower(Left(Name,' + (xfa.event.newText.length) + ')) == "' + xfa.event.newText.toLowerCase() + '"]');
    and

    list = xfa.datasets.Countries2.resolveNodes('Country.[At(Lower(Name),Lower("'+xfa.event. newText+'")) > 0]');

    If you are still having trouble post a link to your form and I'll have a look.

    Regards

    Bruce

    ReplyDelete
    Replies
    1. Unfortunately, I'm still only allowed to enter one text box. Here's a link:
      https://www3.mydocsonline.com/Share.aspx?-099JijTL2P53EMB06Zc%2Fn5vgQ

      Delete
    2. To further elaborate, what I ultimately need to happen is have a text box beside each list box that will pull up a condition [the "region", i.e., the location of condition is really moot]. The condition then is used in a script to combine with a dropdown for "eye" or "severity" to then result in an ICD code in a separate text box. I've included the PDF that I will need to insert the "searchable dropdown" into to achieve this as well. Thanks again. This is all really really new to me.
      Final PDF template: https://www3.mydocsonline.com/Share.aspx?-445PB1iZWisrmLXpe%2F7PGR1Jw

      Delete
    3. Hi,

      Under the xfa:datasets there is also generally a xfa:data element for the default data connection and dd:dataDescription for the data description that goes with it. These should occur once. In duplicating the Countries element you have also duplicated the other two. Here is a sample with the duplicates removed. https://sites.google.com/site/livecycledesignercookbooks/home/modified%20countries.working.pdf?attredirects=0&d=1

      Regards

      Bruce

      Delete
    4. I hate to take your time further, but it still only lets you select from one list box. Once a selection is made in either, the other then will not have the listbox open. I've been going through line by line, but I must be missing something.

      Delete
  5. Solved it. Now to figure out the conditional script. Thanks again for the help!

    ReplyDelete
    Replies
    1. Could you tell us, how you solved it ? I am having the same problem

      Delete
  6. This comment has been removed by the author.

    ReplyDelete