Programming list and combo fields in Acrobat and LiveCycle forms - Part 2 of 2

Learn how to add or delete individual items from a list using Acrobat and LiveCycle Designer.

By Thom Parker – October 19, 2007

 

Scope: All Acrobat Full versions (not Standard) and LiveCycle Designer
Skill Level: Beginner

Prerequisites: Familiarity with Acrobat and LiveCycle forms

In Part 1 of this article, we learned how to populate the list in a Combo Box field and how to use the Keystroke (Change) event and the event object to capture the user’s selection. In this part, we’ll look at a slightly different scenario where individual items are added or deleted from a list. The example is an e-mail distribution list that demonstrates how items can be copied from one list to another. It also includes other interesting code for handling List fields and some bonus features not discussed in the article. The bonus features include list sorting and adding double-click selection to the List field.

Example 2: Manipulating individual list items

Example files:

AcroForm
ListProgramming_Part2_AcroForm.pdf

XFA (LiveCycle) Form
ListProgramming_Part2_XFAForm.pdf

This example consists of two List fields and three buttons (Figure 1). One List field is the Master list. It contains a list of departments, each with an associated email address as the export value. This list does not change. The second List field is a Distribution list. It contains the list of departments to which the form will be distributed. Initially, the Distribution list is empty and the user adds departments to it from the Master list by selecting an item and pressing the “Add” button. An entry can be added only once; a second attempt to add the same entry is ignored. Buttons are provided for deleting items from the list and clearing the list. There are also two text fields, one for each List field. When an item is selected in either List field, the Email (export value) of the selected item is displayed in the associated text field.

Figure 1 – Manipulating individual list items

To implement this dynamic email distribution list, we need the ability to add and delete individual items to and from a List field. Both forms technologies provide us with easy-to-use functions for this, but we have another problem. To make the form user-friendly, we need to keep the selection current with the user’s actions. For example, if the user deletes an item, the selection should move to the next item. Unless it was the last item removed, the selection needs to be placed on the new last item. There are several issues like this in list handling, so we need to be careful with our coding.

AcroForm solution

As in the example in Part 1, the supporting functions are placed in a Document Level script, but in this case the Master list is a form field, so there is no Master list variable. For the main features, functions are needed for adding a unique list item, deleting a list item, and clearing the list. We also need a function to populate the “Email Contact” fields when an item is selected from the list.

Fortunately, Acrobat JavaScript provides functions for deleting a list item and clearing the list, so these are in the bag. There is also a function for inserting a list item, but in order to guarantee the item is unique, we need to search the list first, which requires a custom function.

Adding an item to the Distribution list

Here’s the Document Level support function:

function AddUniqueEntryToDistrList(cEntry) {
	// Acquire the Distribution List Field
	var oFld = this.getField("DistributeList");
	// Make sure entry does not already exist
	// by comparing it to all the existing entries
	var bFound = false; for(var index=0;index<oFld.numItems;index++) {
		if(oFld.getItemAt(index,false) == cEntry) {
			bFound = true; break;
		}
	} if(!bFound) {
		// Insert entry at end of list
		oFld.insertItemAt({cName:cEntry, nIdx:-1});
	}
}

The number of items in the List field is provided with the field.numItems property. The item text for doing the comparison is acquired with field.getItemAt(nIndx,bExportValue). The function returns the export value if the bExportValue input is true.

This function is called from the Mouse Up event on the “Add” button, after the selection from the Master list is acquired.

Mouse Up event script:

var oFld = this.getField("MasterList");
if(oFld) {
	// Acquire Selection from Master list
	var cEntry = oFld.getItemAt(oFld.currentValueIndices,false);
	AddUniqueEntryToDistrList(cEntry);
}

The code acquires the text for the selected item and passes it into the AddUniqueEntryToDistrList()function. Notice the index for the selected item is provided by the Field.currentValueIndices property. For single selection lists, this property is an integer. If the List field was set up for multiple selections, this property would return an array of selected item indices and the code would need to be slightly different.

The AddUniqueEntryToDistrList()function is also used in the double-click bonus feature. Adding entries to the Distribution list occurs when an item on the Master list is double-clicked. The AddUniqueEntryToDistrList() function was deliberately written to work in either situation, from the “Add” button or a double-click. The implementation for the double-click feature is not covered here and is left as an exercise for the reader.

Deleting an item from the Distribution list

Deletion is accomplished by the user selecting an item from the Distribution list and pressing the “Delete” button. The code for this is very simple. However, when the item is deleted, the selection also disappears. As a convenience for the user, the selection should be maintained and placed on the item that replaces the deleted one. Here is the code for the Mouse Up event of the Delete button:

var oFld = this.getField("DistributeList");
var prev = oFld.currentValueIndices;
// check for valid selection
if(oFld.currentValueIndices > -1) {
	oFld.deleteItemAt(oFld.currentValueIndices);
	// If last item was deleted then place selection on new last item.
	// Otherwise, place it on the item with the same index.
	if(oFld.numItems > prev) oFld.currentValueIndices = prev;
	else if(oFld.numItems > 0) oFld.currentValueIndices = prev-1;
}

Clearing the list

This is a simple one-liner. Here’s the code in the Mouse Up event for the clear button:

this.getField("DistributeList").clearItems();

Placing email text into the “Contact Email” field when a list item is selected

This is implemented for both List fields, but only the Master list contains the e-mail addresses as an export value. The Distribution list contains only the department names. The solution for the Master list is trivial and the solution for the Distribution list requires some code. It is impossible to write an efficient, generalized function to cover both cases, so we’ll handle each one individually.

For the Master list, these two lines of code in the change event will do the trick:

if(!event.willCommit)

this.getField("MasterEmail").value = event.changeEx;

The export value for the change is held in the event.changeEx property. This script simply assigns it to the Email Contact field.


For the Distribution list, the Email value has to be acquired from the Master list, and to do this we need to write a small search function. Here’s the function (it’s declared in the Example2 Document Script in the sample file):

function GetMasterExport(cEntry) {
	// Acquire the Master List Field
	var oFld = this.getField("MasterList"); for(var index=0;index<oFld.numItems;index++) {
		// If item matches, then return the export value
		if(oFld.getItemAt(i,false) == cEntry) return oFld.getItemAt(index,true);
	}
	return null;
}
//This function is called from the change event of the Distribution list field:
if(event.willCommit) {
	if(event.value){
		this.getField("DistrEmail").value = GetMasterExport(event.value);
	}else{
		this.getField("DistrEmail").value = "";
	}
}

In the code above, the selection is checked for a null value, whereas this was not done for the Master list code because the Distribute list can be cleared, and the Master list cannot. When the list is cleared, a change event is fired with a null value for event.value. This case is handled by clearing the email field.

See the full implementation of this list functionality in ListProgramming_Part2_AcroForm.pdf.” Supporting functions are in the “Example2” document script. The sample file also contains some bonus features — a double-click action, and move-item-up and move-item-down buttons for sorting the Distribution list.



XFA form solution

XFA JavaScript has a slightly different method for handling List fields. Some of the things we wrote functions for in the AcroForm code are built into XFA JavaScript, but some of the one-line functionality available in AcroForms do not exist in XFA, so it’s a trade-off.

Support functions in XFA forms are stored in Scripting Objects. The Scripting Object for this example is named Example2 and is attached to the “FormSection” subform, which is the parent subform containing the list and button fields.

Adding an item to the Distribution list

The support function for adding unique entries to the Distribution list is not significantly different from the same function in the AcroForm code.

function AddUniqueEntryToDistrList(cEntry) {
	// to get the number of list entries we have to acquire
	// the actual item list from the XML
	var oList = FormSection.resolveNode("DistributeList.#items");
	// Make sure entry does not already exist
	var bFound = false; for(var index=0;index<oList.nodes.length;index++) {
		if(oList.nodes.item(index).value == cEntry) {
			bFound = true; break;
		}
	}
	if(!bFound) DistributeList.addItem(cEntry);
}

XFA JavaScript does not provide a property for getting the number of items in the list. Instead, we have to use the resolveNode function to search for, and acquire, the actual list entries from the XML. In this code, these items are also used for the comparison. It works here because there are no export values, but typically it is better to use the official functions for acquiring the display text (getDisplayItem()) and export text (getSavedIem() and boundItem()).

XFA JavaScript also does not provide an item-insertion function. The addItem() function only appends items to the end of the list. This means ordering items requires clearing and rebuilding the list. Code for this is in the Move-Up and Move-Down buttons in the sample file, ListProgramming_Part2_XFAForm.pdf. These are bonus features not discussed here.

The AddUniqueEntryToDistrList() function is called from both the “Add” button and one of the bonus features, the double-click logic, which is not discussed here.

Here is the code in the Click event of the “Add” button:

if(MasterList.selectedIndex> -1)
Example2.AddUniqueEntryToDistrList(
    MasterList.getDisplayItem(MasterList.selectedIndex)
);

The selectedIndex property of the List Object holds the index of the first selection. It does not handle multiple selections, which is OK since the lists in the example are single selection. The code first checks for a valid selection, then acquires the selection display text with the getDisplayItem() function and passes the return value into our AddUniqueEntryToDistrList() function. Notice the add-entry function is prefixed with Example2. This is the name of the Scripting Object where the function is defined.

Deleting an item from the Distribution list

Deletion is handled in the XFA form exactly the same way it is done in the AcroForm. Of course, the names of the List field properties and functions are different, but this is superficial. The only real difference is that the Contact Email field has to be cleared. This is because the List box does not receive a Change event when an item is deleted, as it did in the AcroForm example. It has to be cleared explicitly.

var nItems = DistributeList.resolveNode("#items").nodes.length;
var nSel = DistributeList.selectedIndex;
if(nSel > -1) {
	DistributeList.deleteItem(nSel);
	if((nItems-1) > nSel){
		DistributeList.selectedIndex = nSel;
	}else{
		DistributeList.selectedIndex = nSel-1;
		DistributeEmail.rawValue = "";
	}
}

Clearing the list

Like the AcroForm code, this one is very simple. Here’s the code in the Click event for the “Clear” button:

DistributeList.clearItems();

DistributeEmail.rawValue = "";

Placing e-mail text into the “Contact Email” field when a list item is selected

As in the AcroForm code, this feature is implemented for both form lists. But unlike the AcroForm code, the implementation is trivial for both the Master list and the Distribution list. Here’s the code for the Change event of the Master list:

MasterEmail.rawValue = xfa.event.newText;

The xfa.event.newText property holds the export value of the selection, not the display value. The XFA event object does not provide the display value at all. If our code needed it, we would have to write a special function.

Here is the code for the Change Event of the Distribution list:

DistributeEmail.rawValue = MasterList.boundItem(xfa.event.newText);

Notice the xfa.event.newText property is used here to get the display value of the selected item on the Distribution list. The Distribution list does not have any export values, so this property can only return the display value.

The boundItem() function takes a display value as input and returns the associated export value, i.e., the e-mail address from the Master list. This is much simpler than the method used in the AcroForm code for the same feature.

See the full implementation of this list functionality in ListProgramming_Part2_XFAForm.pdf”. Supporting functions, and the bonus functions previously mentioned, are in the “Example2” Scripting object attached to the “FormSection” subform.

Summary

So now you know everything there is to know about Combo Boxes and List Fields in both AcroForms and XFA Forms. Well, maybe not everything, but you should have enough information to do just about anything you want. We covered List Events, acquiring and setting both display and export values, deleting list items, and the examples include some advanced bonus features.

Documentation on the functions used in these scripts can be found at:

1 Acrobat JavaScript Reference
https://www.adobe.com/devnet/acrobat.html



Related topics:

PDF Forms, JavaScript

Top Searches:


2 comments

Comments for this tutorial are now closed.

Lori Kassuba

1, 2013-11-01 01, 2013

Hi locastillo,

Unfortunately you cannot change the blue highlight color in a list form field.

Thanks,
Lori

locastillo

9, 2013-08-29 29, 2013

Can you change the light blue color highlight in the Distribution List using an AcroForm?

Comments for this tutorial are now closed.