Scope: All Acrobat Full versions (not Standard) and LiveCycle Designer
Skill Level: Beginner
Prerequisites: Familiarity with Acrobat and LiveCycle forms
There are times when entries in a Combo box or List field need to be changed on the fly. For example, a parts order form might include two drop-down lists (combo fields); one for selecting an assembly and one for selecting a part within the assembly. Each time a different assembly is selected, the list of parts needs to be changed to reflect the correct assembly parts for that selection.
A different scenario is where individual items are added or deleted from a list, such as an e-mail distribution list. In this example, the form has two list elements: the master e-mail list and the distribution list. On the form, buttons are provided for both adding and deleting entries to/from the distribution list.
In all cases, manipulating list entries requires scripting. In this two-part article, we’ll explore programming options for both scenarios outlined above. In Part 1 (this one), we’ll learn about using list events and re-populating the list entries. In Part 2, we’ll learn about modifying list entries one at a time. Sample code for both Acrobat forms (AcroForms) and LiveCycle Designer forms (XFA forms) is provided in the article. Each of the example files contains more complete code than is presented in this article along with some bonus scripts for doing more advanced list manipulation.
General list operations
Before getting into the nitty-gritty details of each example, let’s take a higher-level view and look at some programming features shared by all list fields, regardless of forms technology. A List field, as the name implies, is a list of items sorted into some order. The user interacts with a List field by selecting one or more items from it. Typically, there will be a display string and an export value assigned to each list item. For both AcroForms and XFA forms, the export value is a string. Finally, a list should have some properties for controlling how it behaves.
While each of the forms technologies has its own diverse set of properties, two common list properties are a parameter for making the list single or multiple selection, and a parameter for controlling how item selections are committed. Committing is the process of taking the selections made by the user and applying them to the value of the field. This can be done when the focus is moved to another field, or immediately when the user makes a selection.
To manipulate a list programmatically there must be functions or properties to:
Each forms technology has a different way of handling these features. Unfortunately, neither does a very good job of providing good functions for all the items listed above. However, both forms technologies do have enough support functions that it only takes a little extra coding to cover the holes.
Part 1- List Events, populating and clearing a list
Example files:
In this example, we’ll use a parts order form with two drop-down lists on each order line, as shown in Figure 1. (see page 1 in the example files). The first drop-down list selects the Assembly. The second drop-down is a list of parts for that assembly. Obviously, the parts list must change each time the Assembly selection changes.
Figure 1: Order form using two lists. Assembly selection changes entries on parts list.
In order to do this, we need a master list of lists. This master list must contain all the parts lists for each assembly type all the part prices. We’ll use an object literal stored somewhere in the document to accomplish this. The location where the master list is declared is different for each of the two forms technologies, but the list itself is the same.
var oAssemblyParts = { Chasis: [ ["-","None"], ["Rear Bracket",205.95], ["Front Bracket",185.95], ["Long Support",44.95], ["Front Bearing",48.95] ], Clutch: [ ["-","None"], ["Plate 1",15.95], ["Plate 2",22.95], ["Inside Shaft",44.95], ["Outside Shaft",32.95] ], Brake: [ ["-","None"], ["Master Cylindar",139.95], ["Slave Cylindar",85.95], ["Pad",15.95], ["High Presure line",22.95] ], Coolant: [ ["-","None"], ["Pump",35.95], ["Thermostat",19.95], ["Coolant Line",8.95], ["Reservoir",17.95] ] };
Each entry in the object is a name/value pair separated by a colon “:”. The name is the Assembly name. The value is an array of the items for the parts list. Each item is small array containing the part name and the price. For example, use this code to get the item list for the “Clutch” assembly:
var clutchItems = oAssemblyParts["Clutch"];
To get the price of the “Plate” in the “Clutch” assembly, use this code:
var nPlatePrice = clutchItems[2][1];
We’ll also need a way to trigger the script that modifies the parts list. Each List field receives a number of events from Acrobat. There are events for Mouse Up, Mouse Down, On Focus and more. We’ll use the change event on the Assembly list to re-populate the parts list from the master list object. Both AcroForm and XFA Forms have this event and use it in approximately the same way. The change event is triggered when the user selects a list entry.
AcroForm solution
In AcroForms, the master list and all the supporting functions are placed in a Document Level Script. This is the standard location in an AcroForm for doing initialization and set-up activities.
The first supporting function is for setting the part entries. Fortunately, the master list contains the part/price information in exactly the right format for the function that populates a List field. The only other thing we have to be concerned about is handling the case where no Assembly is selected. In that case, we need to clear the list. Here’s the code:
function SetPartEntries() { if(event.willCommit) { // Get the new parts list from the Master List // Since the selection is being committed, // event.value contains the Assembly name var lst = oAssemblyParts[event.value]; // Clear the Parts list if there are no parts for the selected assembly if( (lst != null) && (lst.length > 0) ) this.getField("PartSelect").setItems(lst); else this.getField("PartSelect").clearItems(); // We have a new parts lists and the first entry is // is a non-selection, so clear the price field. this.getField("Price").value = 0; } }
Notice that the AcroForms model provides a single function for setting all items in the list. We simplified our programming task by formatting the master list to take advantage of this function, the “field.setItems()” function.
To use our “SetPartEntries()” function, simply call it from a the Keystroke Event of the Assembly list field, like this:
SetPartEntries();
The Keystroke event is called whenever the user changes the list selection, so in this case it’s really the Change event, which could be caused by a mouse action or by a keystroke.
The only other general-purpose function we need is one to handle populating the Price field when a part is selected:
function SetPriceValue(){ // In order to get easy access to the export value, i.e. Price. This // function needs to be run on the un-committed change event. // This field is set up for Commit on select so we know the value // will be committed anyway. if(!event.willCommit){ // If the export value is Not a Number then // set the price to zero. var nSelExp = 0; if(!isNaN(event.changeEx)) nSelExp = event.changeEx this.getField("Price").value = nSelExp; } }
In AcroForms, there are two kinds of Change events: Committed and Uncommitted. The difference between these two is more important for Text fields than it is for List fields, but for this function, we specifically want the Uncommitted Change event because this event makes the export (i.e., price) value available to us through the “event.changeEx” property. This is a matter of convenience, since it would only take a few more lines of code if we were to use the Committed Change event.
To use the “SetPriceValue()” function, simply call it from the Keystroke Event of the Parts list field, like this:
SetPriceValue()
The full implementation for this example can be found in the example file, “ListProgramming_Part1_AcroForm.pdf.” In this file, there are three order lines so the two general-purpose functions (SetPartEntries() and SetPriceValue()) are written in a more generic way to work with any of the drop-down lists in any line. This is done with creative field naming. Always pay close attention to how you name form fields. There is a direct relationship between the names you choose for the fields and how easy it is to program the form.
XFA-form solution
In an XFA form, the master list and support functions are placed in a Scripting object. The Scripting object can be attached to any sub-form in the form hierarchy, but the best location is on a parent sub-form close to the fields it will be working with, i.e., the parent of the order row, which is where it is located in the example file, “ListProgramming_Part1_XFAForm.pdf.”
There are several advantages to using LiveCycle Designer for this example. The number one reason is that no special code is required for handling multiple order rows like there was in the AcroForms example. Each row is in its own sub-form and the code only needs to reference fields in the same row. Another advantage is that rows can be added to the form dynamically.
Unfortunately, the list programming model for XFA is not that great. There is no function for populating the List field with all new entries like there is in AcroForms. The entries have to be added individually. Here is what our function for setting the part entries looks like in an XFA Form:
function SetPartEntries(){ // Since entries are added one at a time it is necessary to // clear out the list first. PartList.clearItems(); // The ComboBox value is not dependent on the list selection // so this also has to be cleared. PartList.rawValue = null; Price.rawValue = 0; // Grab the list of parts from the Master list and loop // over it to add entries into the Parts List Field. var aParts = oAssemblyParts[xfa.event.change]; if(aParts && aParts.length){ for(var i=0;i<aParts.length;i++){ PartList.addItem(aParts[i][0],aParts[i][1].toString()); } } }
In XFA JavaScript, it is the "xfa.event.change" property that holds the text for the new selection. Another difference between this code and the AcroForm code is the parts list and the price field have to be explicitly cleared.
To use this function, simply call it from the Change event of the Assembly list, like this: SetPartEntries(); To populate the price field, we use a function very similar to what was used in the AcroForm code, with one main difference. In XFA JavaScript, the “boundItem()” function is used to retrieve the export value from the selection text. Here’s the code:
function SetPriceValue(){ // If the export value is null or not a number // then set the price to 0. var newPrice = 0; newPrice = PartList.boundItem(xfa.event.newText); if(isNaN(newPrice)){ newPrice = 0; Price.rawValue = newPrice; } }
To use this function, call it from the Change event of the Part List field, like this:
SetPriceValue();
The full implementation for this example can be found on page one of “ListProgramming_Part1_XFAForm.pdf.”
Summary
In this article, we learned how to use the Keystroke event and the event object to instantly capture the user’s selection on a Combo Box field. This was done for two different Combo Box fields. In one case, the selection was used to re-populate the list on another Combo Box. In the other case, the selection was used to set a field value.
In Part two of this article, we’ll delve deeper in to the mysteries of List fields, taking a look at list sorting and how individual items can be added to or deleted from a List or Combo Box field.
1 Acrobat JavaScript Reference
http://www.adobe.com/devnet/acrobat/
2 XFA Object Reference
http://partners.adobe.com/public/developer/xml/topic.html
Related topics: |
PDF Forms, JavaScript |
Top Searches: |
Convert existing forms to fillable PDFs fill and sign any formEdit PDF create PDF Action Wizard |
Try Acrobat DC
Get started >
Learn how to
edit PDF.
Post, discuss and be part of the Acrobat community.
Join now >
15 comments
Comments for this tutorial are now closed.
Lori Kassuba
2, 2015-06-24 24, 2015Hi hitesh solanki,
I would suggest you post your question here and select the JavaScript category:
https://answers.acrobatusers.com/AskQuestion.aspx
Thanks,
Lori
hitesh solanki
4, 2015-06-12 12, 2015dear all
i am trying to create a editable pdf , in which i have problem.
I want to validate two combo box i.e. based on the value of one combobox the coresponding change in list of item should be there.
I dont know java scipt. if anyone could help me..
Lori Kassuba
3, 2013-09-03 03, 2013Hi Clare,
In an Acrobat form, the master list and all the supporting functions are placed in a Document Level Script. This is the standard location in an AcroForm for doing initialization and set-up activities. Here is a tutorial on Document Level Scripts:
http://acrobatusers.com/tutorials/js_document_scripts
Thanks,
Lori
Clare Rome
1, 2013-08-16 16, 2013Hi,
I am completely new to PDF Forms and have been trying to work this out for the whole 2 days I’ve been using it, I am also trying to create an order form just like the one in your example. This might sound like a silly question but where do i put the master list?
Thanks
Chris
10, 2013-07-19 19, 2013Hello, great post by the way. I need to create longer lists. For example, I have three items for the first drop down and for each of those items, it is associated with all the states and a price. 150 items seems to be too long for the variable. Any other options?
Mike Robles
5, 2013-04-13 13, 2013Thom, I want to use multi-word AssemblyParts (separated by spaces) such as ‘Cylinder Ring’, ‘Brake Pads’, etc, but I can’t figure out how to do it, since individual parts are arrays, I can’t have spaces. Any advise? thank you.
Thom Parker
5, 2013-03-05 05, 2013Read this article:
http://acrobatusers.com/tutorials/so-where-does-javascript-go-in-acrobat
Marguerite Stephens
2, 2013-02-25 25, 2013Thom, Thank you for your advice. I have searched and not found what I most desperately need or I am missing the whole thing.
Where do I write the script and save the script? In MS Word, you used a module to write and save the script for VBA. I am really having a problem with WHERE to write the JS script and how to save it.
My apologies Lori for posting the question in the incorrect area. I am looking for help to accomplish this task.
I have used Acrobat X to convert my Word forms to PDF forms. But they were rather simple as they did not have anything but form fields. The Word form that I recently did using VBA was the first time doing it. First time using VBA. It worked really swell until someone with MS Word 2008 couldn’t get it to work. (sigh)
I am thinking since I have 3 ddboxes off one I need my master list to show Region ?: 3 different times. I don’t understand the master list, unless it is akin to the VBA code where you type in everything starting with Add. “” for every item.
I am persistant but am struggling.
Thanks for your replies
Lori Kassuba
8, 2013-02-19 19, 2013Hi Marguerite,
Can you post your question to the Experts here:
http://answers.acrobatusers.com/AskQuestion.aspx
Be sure to choose the JavaScript category.
Thanks,
Lori
Thom Parker
5, 2013-02-19 19, 2013Marguerite,
If you picked up VBA, and you’ll easily be able to pickup JavaScript. But you do need some introductory material into both JavaScript, and the Acrobat scripting model. They are two very different things. You’ll find some basic material on this site about Acrobat in the tutorials. Do a search in the tutorials on the phrase “Where is”.
You’ll also be interested in the free videos at www.pdfscripting.com, which explain many of the basic concepts, and are much better organized.
http://www.pdfscripting.com/public/Free_Videos.cfm
Marguerite
6, 2013-02-13 13, 2013I want to do the combo boxes but am so lost
I want the first box (Assembly) to be Region, that box will be populated with A; B; C; D; E; F
I want the Region box to populate the District box, the RegRep box and the RegFac box depending on which Region is chosen (It needs to populate these 3)
I then need to have the district box, once a district is chosen, to populate the school box
I then need to have the school box, once a school is chosen, to populate the strategist box
I did this in Word 2011 using VBA and it works great, UNTIL someone with an older version of MS Word tries to open and fill it in. (sigh)
So, found that the Adobe Acrobat X MAY be able to do this.
I have two hurdles:
1. I know nothing of JavaScript (I didn’t know VBA either)
2. I do not know where to start ‘writing’ the script once I have JS figured out.
Do I open Document JavaScripts? Have tried that, I type in a script name, add, but can’t seem to type in the box. So I go to Edit, but when I type in a few lines to see what it will do, I close it, reopen, and it is gone, so I don’t know how to save it.
I need some mega help.
What does var stand for?
oAssemblyParts?
WG Meisheid
12, 2013-01-08 08, 2013I tried a simpler two dropdown setup but I cannot get it to work. I don’t get an error in the Debugger but nothing populates in the second dropdown.
Here is the code.
var oCategorizations = {
AV_Issue: [[”-”,“None”], [“Video/Porjector Issue”], [“Screen Issue”], [“Wireless Control Issue”], [“TV/Monitor Issue”]],
IT_Hardware_Issue: [[”-”,“None”], [“Desktop Hardware Issue”], [“Laptop Hardware Issue”], [“Printer Hardware Issue”], [“Server Hardware Issue”], [“Hand Held Hardware Issue”], [“Component Issue”], [“Computer Equipment”], [“Other IT Hardware Issue”]],
Network_Issue: [[”-”,“None”], [“Security Issue”], [“Network Service”],
[“WAN”],[“CAN”], [“Lan Issue”], [“Internet”]],
IT_Software_Issue: [[”-”,“None”], [“Software”], [“Email Issue”], [“Application Issue”], [“Operating Systej Issue”], [“Other Sofeware Issue”]],
Office_Equip: [[”-”,“None”], [“Copier/MFD”], [“Fax Machine”], [“Shredder Issue”],[“Other Office Equipment Issue”]],
Telecom_Issue: [[”-”,“None”], [“Satellite Issue”], [“Cellular Issue”], [“Telephone Issues”],[“VTC Issues”],[“Other Telecom Issues”]]
};
function SetClassification()
{
if(event.willCommit)
{
// Get the Categorizationz list from the Master List
// Since the selection is being committed,
// event.value contains the Assembly name
var lst = oCategorizations[event.value];
// Clear the Parts list if there are no parts for the selected assembly
if( (lst != null) && (lst.length > 0) )
this.getField(“Classification”).setItems(lst);
else
this.getField(“Classification”).clearItems();
}
}
jesus siemens
6, 2012-11-08 08, 2012CORRECTED :
based on your work ( gracias ) i did this form :
Jesús.Siemens.#variables[0].Familia - (JavaScript, client)
var FESn = {
Jesús: [ [“Jesús (me)”], [“Michael”], [“Mary Celeste”], [“Montserrat”]],
Wilberth: [ [“Henry”], [“Lucy”]],
Mary: [ [“Rose”], [“MaryJo”]]
};
// Jesús , Wilberth & Mary are the 1st dropdown
// Jesús (me) , Lucy , Rose , etc. are 2nd dropdown
// How to do the 3rd dropdown , our next generation ?
// SelecHijo()
function SelecHijo()
{
Nietos.clearItems();
Nietos.rawValue = null;
var aParent = FESn[xfa.event.change];
if(aParent && aParent.length)
{
for(var i=0;i<aParent.length;i++)
Nietos.addItem(aParent[i][0].toString());
}
}
// SelecNieto()
function SelecNieto()
Jesús.Siemens.Hijos::change - (JavaScript, client)
Familia.SelecHijo();
Jesús.Siemens.Nietos::change - (JavaScript, client)
Familia.SelecNieto();
// it refers to my grandfa family ( Familia de Eddy Siemens FESn ) :
1st dropdown : my father and his brothers .
2nd dropdown : my brothers , cousins and i
how to do the 3rd dropdown , my sons , nephew and cousin sons ?
this form works on Adobe Livecycle .
there are 3 dropdown lists : Hijos , Nietos & Bisnietos
Thom Parker
8, 2012-11-07 07, 2012Follow the pattern. Each list has an associated object that provides the options for a selection. The selections are essentially a tree. So the associated objects must also form a tree. Where each branch forms a selection path that provides the list data for the next dropdown. This is much to complicated to explain in a comment. You should join www.pdfscripting.com and download the list samples there.
jesus siemens
7, 2012-11-07 07, 2012based on your work i did this form :
Jesús.Siemens.#variables[0].Familia - (JavaScript, client)
var FESn = {
Jesús: [ [“Jesús (me)”], [“Michael”], [“Mary Celeste”], [“Montserrat”]],
Wilberth: [ [“Henry”], [“Lucy”]],
Mary: [ [“Rose”], [“MaryJo”]] // How do I include // the children of Rose and Mary ( Third dropdown Bisnieto ) ?
};
// SelecHijo()
function SelecHijo()
{
Nietos.clearItems();
Nietos.rawValue = null;
var aParts = FESn[xfa.event.change];
if(aParent && aParent.length)
{
for(var i=0;i<aParent.length;i++)
Nietos.addItem(aParent[i][0].toString());
}
}
// SelecNieto()
function SelecNieto()
Jesús.Siemens.Hijos::change - (JavaScript, client)
Familia.SelecHijo();
Jesús.Siemens.Nietos::change - (JavaScript, client)
Familia.SelecNieto();
// it refers to my grandfather family :
1st dropdown : my father and his brother .
2nd dropdown : my brothers , cousins and i
how to do the 3rd dropdown , my sons , nephew and cousin sons ?
this form works on Adobe Livecycle
jesus siemens
6, 2012-11-06 06, 2012in this example are 5 fields : Assembly , Parts , Price , Quantity and Total . Assembly and Parts are linked dropdown lists ( You can select any option of many in both ) . Price is incluided with Part ( [“Rear Bracket”,205.95], the same list ) . Quantity is provides by user and Total is an Math Operation .
how to link a third dropdown list ?
Gracias . . .
Comments for this tutorial are now closed.