Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

'Scripting' Category Archive

Previewing as Dynamic PDF

Have you ever lived through the frustration of previewing a form on which you’ve written a simple little script to affect the presence of an object when a button is clicked and pulling your hair out because you keep clicking on the button and nothing happens (object doesn’t disappear, there’s no error message, etc.)? Or maybe you’ve been in a situation where you’ve added script to a button in order to insert a new instance of a repeatable subform and while clicking on the button doesn’t produce one, the submitted XML data file contains entries for each new instance that was added?

Even if you haven’t, it may happen someday so here’s the remedy for the case of the “Common (Static PDF) Flue”…

In Designer, there are two different locations containing settings which affect the type of temporary PDF file created when you click on the Preview tab:

  1. Under the “File Options” section within the “Document Handling” panel of the “Tools | Options” dialog, you can set the Default File Type for New Forms. This type is used on new forms which you preview prior to saving (because Designer doesn’t know which format you’ll use at the time of preview). This is set to a static PDF format by default.
  2. Even if you’ve specified a dynamic PDF format for the Default File Type for New Forms, this setting may be overridden by the Preview Type and XDP Preview Format properties in the “File | Form Properties” dialog in the “Defaults” panel once you’ve saved your form. The Preview Type property, set to “Interactive” by default, determines whether the form will be previewed as an interactive (dynamic) form or as a print (static) form. This property supersedes the PDF format. The XDP Preview Format property usually picks-up the Default File Type for New Forms setting and determines what PDF format will be used to preview your form should it be saved as an XDP. (Note that if you’ve saved your form as a PDF file, then the XDP Preview Format setting is ignored).

Now that we’ve covered the different properties which affect the PDF preview format, here’s how to kick that flue I was talking about earlier (so that you actually do preview in a dynamic PDF format and stop pulling your hair out):

  1. If you haven’t saved your form, make sure the Preview Type is set to “Interactive” and that the Default File Type for New Forms is set to a dynamic PDF format. You may also want to set the XDP Preview Format to a dynamic PDF format while you’re at it.
  2. If you’ve saved your form as a dynamic PDF, make sure the Preview Type is set to “Interactive”.
  3. If you’ve saved your form as a static PDF, none of these settings will help you. You must first save your form as a dynamic PDF.
  4. If you’ve saved your form as an XDP, make sure the Preview Type is set to “Interactive” and the XDP Preview Format is set to a dynamic PDF format.
  5. If you’re tired of running into these problems and want to avoid them in the future, just set your Default File Type for New Forms to a dynamic PDF format.

I hope this tip improves your form design health. It did wonders for me!

Updated: January 27, 2007


Posted by Stefan Cameron on July 24th, 2006
Filed under Debugging,Designer,Scripting

Form Variable Tip

Form Variables can be useful because you can store string values into them that are persisted across object events as opposed to variables created locally (within scripted events) which are destroyed at the end of every event.

You can create Form Variables by going to the Variables tab within the Form Properties dialog, accessed via the main File menu.

The catch is in the way you get and set their values: If you’re writing a FormCalc script, then you can manipulate them just like any other variable. For example, let’s say you define one named “MyVar”. In your script, you can then write

MyVar = "test"

to assign the value “test” to it and you can write

xfa.host.messageBox(MyVar)

to display its value in a message box.

If you were then to change the script’s language to JavaScript and attempted to display the variable’s value in a message box as above, you would get the following error:

GeneralError: Operation failed.
XFAObject.messageBox:1:XFA:form1[0].#subform[0].Button1[0]:click
Argument mismatch in property or function argument

This is because FormCalc helps you by doing things “under the hood” based on the context in order to get and set the value of a Form Variable whereas JavaScript doesn’t.

If you look at the XFA definition of the variable, it looks like this:

<variables>
  <text name="MyVar">test</text>
</variables>

This means that the value of the “MyVar” Form Variable is actually contained within the MyVar element’s content which must be accessed via the value property. Therefore, in order to access a Form Variable’s value in JavaScript, you need to do this:

MyVar.value = "test"; // set the value
xfa.host.messageBox(MyVar.value); // get the value

Just like being able to simply write a field’s name like this in a FormCalc script in order to access its value

MyField

as opposed to having to write

MyField.rawValue

in JavaScript, you need to specify the property you’re accessing on the object in JavaScript when accessing the value of a Form Variable (which is always the value property).


Posted by Stefan Cameron on July 16th, 2006
Filed under Scripting

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