Mutually Exclusive Field Validation

| 1 Comment

I got this request yesterday from one of my co-workers.

A form author has 10 items. Let’s say it’s “Ice Cream flavors”…chocolate, strawberry, vanilla,… He wants the form recipients to rank them from most to least favorite. But, he wants to prevent the user from giving two flavors the same rank.

There can’t be two most favorites… unless you’re talking about your children… or dogs in my case.

I knew that this could be done with some pretty heavy script to check all of the fields and build an array of values, compare them, and a bunch of other stuff that I didn’t exactly feel like writing.

Then it occured to me that I could use the fact that Acrobat form fields can be hierarchical and thus treated as an array of fields – this makes it so that the actual validation code can use the field name as the basis for the array and then comparison is easy. It also makes authoring the pertinent form fields practically automatic. It also makes it so that the validation script can be totally abstracted from the document and even the field name itself giving you a truely cut and paste validation script.

First a little more information about Acrobat’s hierarchical fields.

Acrobat form fields can include hierarchical syntax in order to create logical groupings of related fields. For example, the name “name.first” and “name.last” implies that the form field “first” and “last” belong to a group of fields called “name”. The advantage of creating logical hierarchies is that you can enforce consistency among the properties of related form fields by setting the properties of the group, which automatically propagate to all form fields within the group. For example setting the visibility of “name” to “hidden” hides both the “name.first” and “name.last” fields. You can also perform mathematical operations on the array so that if you had a set of fields called “item.1″, “item.2″, and “item.3″, you could get their sum by simply selecting to sum the “item” field.


Click to zoom

This brings be to my next point. When you use the Acrobat Form feature “Place Multiple Fields”, Acrobat automatically creates an array of fields based on the field name of the original field that you had selected. So that your initial field “item”… – See image below.


Click to zoom

Becomes “item.0″ through “item.9″ – See image below.


Click to zoom

So to take full advantage of this capability to create the mutually exclusive field validation effect, use the following steps.

  1. Copy one of the two scripts below – The first is for numeric text fields, the second is for combo-boxes.
  2. Create a form field – you can name it anything you like but don’t make it hierarchical. That is, don’t put a period in the name.
  3. Open the validation tab and paste the code into the custom script area.
  4. If your field is a combo-box, be sure to go to the “options tab” and check the box for “Commit selected value immediately”. This is not absolutely necessary but does provide for a better user experience.
  5. Set the rest of the properties you need.
  6. Now all you need to do is context-click and Place Multiple Fields. Only use one column or row. The script can only handle one dimensional arrays.

Alternatively, you can simply copy the fields out of the example PDF files below and paste them into your own forms.

Here are a couple of example files using the scripts. The scripts themselves are available below.

Mutually Exclusive Numeric Text Fields
Mutually Exclusive Combo-Boxes

Numeric Text Field Version

/*
Javascript Created by Joel Geraci - Acrobat Technical Evangelist - geraci@adobe.com.
*/
//
//get the name of the current field and use it to determine the parent field array
currentFieldName = event.target.name
parentFieldName = currentFieldName.substr(0, currentFieldName.indexOf("."))
//get the parent field
parent = this.getField(parentFieldName);
//now get all the children of the parent field as an array
fields = parent.getArray();
//get the value that was just entered into the field
value = event.value
//did they add a number or delete a number - the field is empty of they deleted
if (value.length > 0)
{
//range check first - you can skip this part if your values are not numeric
if (value > fields.length || value < 1)
{
app.alert("Ranking must be between 1 and "+fields.length)
event.rc = false;
}
else
{
//now compare the value that was entered to the
//values in the rest of the non-blank fields
for each (field in fields)
{
if (field.value != "" && field.name !=event.target.name)
{
if (value == field.value)
{
app.alert("You have already used number "+value+".");
event.rc = false;
}
}
}
}
}

Combo-Box Version

/*
Javascript Created by Joel Geraci - Acrobat Technical Evangelist - geraci@adobe.com.
*/
//
//get the name of the current field and use it to determine the parent field array
currentFieldName = event.target.name
parentFieldName = currentFieldName.substr(0, currentFieldName.indexOf("."))
//get the parent field
parent = this.getField(parentFieldName);
//now get all the children of the parent field as an array
fields = parent.getArray();
//get the value that was just entered into the field
value = event.value
//did they add a number or delete a number - the field is empty of they deleted
if (value != "noSelection")
{
//now compare the value that was entered to the
//values in the rest of the non-blank fields
for each (field in fields)
{
if (field.name != event.target.name)
{
if (value == field.value)
{
app.alert("You have already picked "+value+".");
event.rc = false;
}
}
}
}