Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

'Tutorials' Category Archive

Dynamic Properties

Did you know that as of Designer 7.1, there’s way to automatically populate certain field properties with data without having to write any script? This is what the new Dynamic Properties feature is designed to do.

First, you have to enable it because it’s disabled by default. You can do this by going to the Data Binding panel in the “Tools | Options” dialog. There, you’ll find a check box labeled, “Show Dynamic Properties”. Check the box and press OK. After doing so, put a list box (for example) on the form and take note of the changes in the Object palette’s Field, Value and Binding tabs.

You’ll notice that some property labels have now changed color (default is green) and are underlined. You can now click these property labels to make the properties they pertain to dynamic (i.e. to automatically push values into them when data is loaded into the form via a certain data connection that you specify). For instance, the Field tab now has dynamic Caption and List Items properties.

If you click on the List Items label, you’ll get the following dialog (this screen shot shows the properties already configured for this sample):

Using the Dynamic Property dialog (above), you can then specify the data connection from which the data will be loaded and also the data node(s) that will contain the data (in this case, for a list field, you can bind data nodes to the text and value items of the list).

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat Pro 7.0.5

Note: If you open the form in Acrobat, don’t forget to import the data into it using the “File | Form Data” menu.

For this sample, we’re trying to list all the movie titles and, when a movie is picked from the list, display its show time in a date/time field on the form. Therefore, we’ve bound all movie data

$record.movie[*]

to the list and then we’ve bound the text items to the

title

data node (which translates to “$record.movie[*].title” since it’s relative to the property’s binding) and the value items to the

showTime

data node (which translates to “$record.movie[*].showTime”).

Based on these settings for the list’s text and value items, the list will be automatically populated with all movie titles and show times when the movie data is imported into the form. All this without having to write a single line of script!

By the way, if you’re curious about the script you would have to write in order to do the equivalent without using the Dynamic Properties feature, just drop a “Data List Box” or “Data Drop Down List” object, from the Library palette’s Custom tab, onto the form and have a look at the script in its Initialize event. Now that’s not simple script! Of course, there are advantages to using script over Dynamic Properties because script is more flexible but in this case, there’s really no need to worry about using script.

Once you’ve filled-in the properties inside the Dynamic Properties dialog for the list box’s List Items property, you’ll notice that the property’s label now has a little “link” icon to signify that the property is bound to nodes in a data connection:

Finally, you just need a single line of script in the list box’s Change event to display a selected movie’s show time in a field on the form (in FormCalc):

ShowTime = $.boundItem(xfa.event.newText)

Please note that the Dynamic Properties feature is still in its early stages therefore it only handles simple data binding situations like the one for this sample. Many customers who’ve discovered this feature attempt to use it in dynamic subforms in order to populate lists with data pertaining to the current record and soon discover that the lists always end-up containing identical record data when they use the Dynamic Properties feature. That’s because the feature simply doesn’t yet support dynamically updating the data node occurrence which is used to populate a list, for example (that is, updating the occurrence of the “$record.movie” binding to a specific occurrence as opposed to always using [*]).


Posted by Stefan Cameron on July 29th, 2006
Filed under Data Binding,Tutorials

Demystifying IM.AddInstance

The definition for the Instance Manager’s addInstance method is as follows:

addInstance( [BOOLEAN param] )

Personally, I find the word param a little vague. I think it should be called merge instead because that would give a clearer indication as to what it stands for: Essentially, if the data you’ve merged into your form has a repeating section that you’ve bound to a repeating (dynamic) subform and not all instances of this repeating data section have been merged into the form’s layout, you can control whether the new instance of the dynamic subform pertaining to that repeating data section will get merged with the next section or not by specifying true (merge — the default) or false (don’t merge — show empty instance) as the parameter value.

Usually, this doesn’t make a difference because you typically merge all instances of a repeating data section into your form and once there are no more data instances to merge, addInstance(true) will yield the same results as addInstance(false): an new empty (no data merged-in) instance.

Consider, however, the case where your form is a report and you’d like to show only a glimpse of the data instead of loading all 2000 instances of a repeating section. If your data was sorted from the most important to the least important, you could significantly improve the performance of your report (with respect to load time) by limiting the number of instances of that repeating data section that are initially merged into your form. Once your form is loaded, it could provide ways for the reader to get more instances if they wish to do so.

This can be achieved by using the Max property on the dynamic subform’s Binding tab in the Object palette along with addInstance(true).

Here’s a sample which has a data connection to an XML Data File that lists movies. There are 16 movies in total but the form limits the number of movies initially displayed to 10 and provides a Show More button. When this button is pressed, the movie dynamic subform’s Max count property, initially set to 10, is incremented by 1 and a new movie instance is added using true as the parameter.

Download Sample [zip]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Note: If you open the form in Acrobat, don’t forget to import the data into it using the “File | Form Data” menu.


Posted by Stefan Cameron on July 8th, 2006
Filed under Instance Manager,Scripting,Tutorials

Sorting Lists at Runtime

Have you ever needed to sort the content of a list box or drop down list at runtime (e.g. in a form loaded in PDF with Acrobat or HTML with a browser)?

Unfortunately, neither the XFA nor the AcroForm Object Models give you either properties or methods to achieve this functionality. The only thing available are Sort Ascending and Sort Descending buttons on the list of items you define in the Object palette’s Field tab in Designer — not very useful at runtime! Say you were loading data from an XML Data File into your form and this was populating a list with values that needed to be sorted: There wouldn’t be a built-in way for you to do that.

The only solution I’m aware of at this time is to flex your scripting muscles and write some functions that’ll get you sorting lists (from either list boxes or drop down lists) and that’s exactly what I did today while replying to a post on Adobe’s Designer Forums:

Download Sample [pdf]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Update: It looks like Acrobat 8.0 broke something that prevents my sample form from working correctly. It has to do with the call to

resolveNodes("#items[*]")

Fortunately, the bug will be fixed in Acrobat’s next release.

As a workaround, I would encourage you to have a look at the new list object properties and methods now available in Acrobat 8.0. You should be able to use a combination of those new properties/methods along with some of the original script in this sample in order to come-up with an update solution that works.

All the code is located in the script object appropriately named, “ScriptObject”.

The idea was to make use of the JavaScript Array object’s built-in sorting function, sort, by giving it a custom sorting function that was able to sort pairs of text and value items. Remember that for XFA choiceList fields, there’s always one <items save=”1”> node but there may be a second <items> node if text and value items are defined.

From Designer’s UI, you define value items by default by entering items in the list on the Object palette’s Field tab. This defines an <items save=”1”> node. If you then go to the Bindings tab and specify values, the items you specified on the Field tab become the “text” items, defined in the second <items> node, and the values are set in the <items save=”1”> node.

When sorting the list, it’s important to maintain the association between text and value item pairs and that’s why the script is a little complex — not to mention the fact that getting items out of an XFA choiceList field (list box or drop down list) isn’t as easy as 1-2-3 either!

So the script attempts to find text and/or value items, create ListItem objects for each pair, sort them using the custom sort function __SortFunction and then replaces the current items in the list with the ones in the sorted order.

Updated: April 11, 2007


Posted by Stefan Cameron on June 29th, 2006
Filed under Scripting,Tutorials

Process All Fields

A common requirement on the Adobe Designer Forums is to find all fields on a form and do something specific with them.

For instance, you may want all mandatory fields to be automatically highlighted when a user attempts to submit a form electronically before having filled all mandatory fields. While Acrobat provides a button to toggle mandatory field highlighting on/off (via the Highlight required fields check box in the yellow Form Field toolbar), Acrobat’s Scripting Object Model doesn’t provide a function to do the same. Therefore, you’re left having to write some script to achieve the same functionality.

Since this is requested so often, I thought I would try to put together some canned script that you can copy and paste into your form in order to instantly have the ability to make changes on everything that’s considered a field on your form.

Download Script [js]
Download Sample [zip]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

The first download is for a JavaScript file which contains the “plug & play” script that you can simply copy & paste into any event handler or script object and immediately start concentrating on what you want to do when you find a button, a check box, a text edit, etc.

It’s divided into two parts: The first (at the top-end of the script) is a series of Field Processor Functions for each field/object type that may be found within a form. Each function receives a reference to the field in question. The second (at the bottom-end of the script) defines the ProcessAllFields function — the brains behind this operation. This function detects the field type and calls the appropriate Field Processor Function.

All you need to do is add script to the Field Processor Function(s) for the field types you need to do stuff with.

The second download contains the JavaScript file along with a sample form which demonstrates how to get from the bare-bones Field Processor Functions and ProcessAllFields function to a solution which finds all non-filled mandatory fields on a form and highlights them with the current Acrobat Highlight Color. You’ll find customized versions of the Field Processor Functions and ProcessAllFields function in the script object (named “ScriptObject” — yes, I know, this is an unbelievably original name!) while the script execution flow begins in the Submit button’s Click event.

When the Submit button is clicked, the form is searched for non-filled (empty) mandatory fields. If such fields are found, they’ll be highlighted, the RemoveHighlight button will be made visible and an error message will be displayed. Otherwise, the Email Submit dialog will open.


Posted by Stefan Cameron on June 26th, 2006
Filed under Scripting,Tutorials

Invalid Flashing Fields

So what’s the use of learning about new toys like AcroForm Objects and AcroForm Field Name Generators if you don’t take the time to play with them? Today felt like the right day to do just that and I came-up with a sample form where invalid fields flash red until the user has entered valid values into them. Only once all fields are valid can the form be submitted.

Update: Check-out the newer version on the new Invalid Flashing Fields 2.0 post.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Note: A basic understanding of AcroForm Objects is required for this sample.

The sample form works like this: When the user clicks on the Submit button, there’s a script which looks at all fields on the form and validates them for valid content. In this particular form, the only requirement is for the fields to be filled (i.e. have non-null values). If all fields are filled, the form is them submitted however, if there’s at least one field which isn’t filled, the first-found non-filled field is set to flash red until the user has filled it.

Since XFA doesn’t natively support flashing fields, this is all done using the Acrobat app, Document and Field objects, discussed in greater detail in my previous post on AcroForm Objects, as well as my AcroForm Field Name Generator code.

When a non-filled field is found, the Submit button’s script will get the AcroForm Field object name for the invalid field and use it to generate a small script which will run every time an Acrobat Timer object expires. This timer is created in the following block of code:

moFlashTimerID = app.setInterval(
    "var f = this.getField('GetAcroFormFieldName(oField)');" +
    "if (color.equal(f.fillColor, color.red))" +
    "{ f.fillColor = [" + moAcroFieldFillColor.toString() + "]; }"

    "else" +
    "{ f.fillColor = color.red; }",
  500);

In this block of code, the Acrobat app object’s setInterval method is used to create a timer which will continously expire at a specific interval (in this case, every 500 milliseconds, or 0.5 seconds) and every time it expires, it’ll execute the code specified in the first parameter. Since the timer’s code will execute within the context of the document from which the setInterval method was called, the this keyword will represent Acrobat Document object pertaining to the form. The GetAcroFormFieldName method can then be used to get the AcroForm Field object name pertaining to the invalid field (oField) which is then passed to the Acrobat Document object’s getField method. From there, the AcroForm Field’s fill color is compared to red: If it’s already red, it’s set to a light gray color; otherwise, it’s set to red.

It’s important to note that the setInterval method returns an Acrobat Interval object which can subsequently be used to cancel the interval timer in order to get the field to stop flashing red once the user has filled it with a value. This object is also required in order to ensure the timer is stopped when the form is closed if the user ever decides to close the form while an invalid field is flashing (see the code in the root subform’s (form1) DocClose event).

Updated: August 15, 2006


Posted by Stefan Cameron on June 18th, 2006
Filed under AcroForm Objects,Scripting,Tutorials