Collected Form Development and Debugging Tips

In this post I have consolidated a bunch of tools and tips for developing and debugging XFA/PDF forms.

Use the console Object Effectively

Always show the console on errors

When your form encounters a JavaScript error, the error text shows up in the console.  But by default the console doesn’t appear — which means you could be getting errors without being aware of them.  To see errors as soon as they happen, configure Acrobat to pop up the console as soon as a message appears.  Under Edit/Preferences, set the options highlighted below…

consoleDialog

 

The console methods

console.println() is an indispensable tool for tracing what is happening in your form script logic.  It is much more effective than xfa.host.messageBox() or app.alert(), since it doesn’t require dismissing a dialog with every message.

Did you know there are other methods on the console object?  clear(), hide(), show().  You might want to place a call to console.clear() when your form initializes.  When it’s time to deploy your form, make sure you haven’t left any extraneous messages in the console.

The Server Alternative

Since the console object is an acrobat-specific tool, you need to use something different to emit trace message for server-based XFA forms.  For the server, use xfa.log.message() to write your message to the server log file.

Trace Function Calls

As long as you’re in the mode of dumping information to the console or log file, you may as well make it as easy as possible.  This blog entry describes a method for tracing the input parameters to JavaScript functions.

Have a look at the data DOM

It’s often useful to see what the data currently looks like.  One way to get there is to add a big text field that displays the data dom.  Give it this one line calculation: xfa.datasets.saveXML("pretty");  Set the field as bind="none".  Now you will have an up-to-date snapshot of the state of the data dom.

Re-factor your form

Design for re-usability.  Develop common patterns that are shared between forms.  Create script frameworks inside script objects.  Put the framework script objects in your fragment library.

Use the Merge/Layout Debugger

If your problems are in merge or layout, then try this.  (Try it even if you’re not having problems with merge/layout — it’s cool.)

Exception Handling

When an exception is thrown and displayed in the console (or in the server log file) the resulting message can be frustratingly cryptic. To get higher quality information (including a stack trace), catch errors and parse them into human-readable text.  There is sample code here to get you started.

String Manipulations

If you are manipulating lots of strings — especially if you’re parsing them, get to know the power of regular expression processing in JavaScript.  Have a look at this regular expression testing tool.

Be Version Aware

If you make extensive use of script objects or if you’ve dabbled in using dynamic properties on XFA objects then get educated about the effects of strict scoping and how it behaves in different versions of XFA and Reader.  Read lots more here and here.

Summarize your form

This post shows how to get a "big picture" summary of the form meta data and the content in the form.

Document your Script

Take the time to properly document your JavaScript methods.  Use JavaDoc conventions. Six months from now when you (or someone else) needs to modify the form, you’ll be glad you took the time to explain your form logic.  To generate a report of all the script in the form, look here.

Reduce and Isolate your problem

If you are struggling with a particular problem, try to reproduce the problem in a new, simplified form.  The act of isolating will often lead to discovering any outside influences are affecting your form behaviour.  If you’re still having the problem in your new simple form, then you have a simplified version of the problem that makes it easier to share with others when you ask for help.

Designer Script Editor

Turn on Line Numbers

In your designer script window, turn on line numbers by right clicking on the script window and selecting "Show line numbers" from the context menu.

Don’t Leave Blank Lines at the Top of your Script

Blank lines at the beginning of a script get trimmed before the JavaScript interpreter processes the code.  If there are blank lines, then any line numbers reported by exceptions won’t agree with the line numbers you see in Designer.

Shortcut Keys

<control>+f — bring up the find dialog. Any highlighted text is automatically used as the find string.  <control>+h — brings up the find/replace dialog.  F3 — find next.  <shift>+F3 — find previous.

Multiple monitors

Convince your boss you need two monitors.  Keep Designer in one monitor and place your script editor and Acrobat console in the second monitor.

"foo.bar is not a function"

Your script makes a call to foo.bar() and you get the mysterious message: "foo.bar is not a function".  But you look in your script object and it sure looks like it is defined.  The problem is that you have a syntax error somewhere in your foo script object.  This prevents the runtime from discovering the foo.bar() function.  When you see this message, run Designer’s script syntax checker.

Declare your Variables

Don’t code: for (i=0, i<myList.length; i++)
Instead, code: for (var i=0, i<myList.length; i++)
The JavaScript interpreters process explicitly declared variables more efficiently.

While you’re at it, use variable names that are unlikely to collide with names of objects on your forms. Such as prefixing variables with a "v" or "n" or "s".  (vObject, nOffset, sStringValue).

Beware of Ambiguous Expressions

If you’re writing code that is intended to be re-usable in multiple forms, beware of potential conflicts between property names and form objects.  For example, the expression subform.border.fill.color becomes ambiguous if this script in a context where the subform has a field child named &quot
;border".  To avoid ambiguity, use the expression: subform["#border"].fill.color.  The hash symbol specifies that what follows is a className instead of a container name.

Find the Root Subform

If you have re-usable script that needs to locate the root subform, you can use this expression:

xfa.form.resolveNode("#subform")

Or the slightly more terse:

xfa.form["#subform"]

Don’t Modify Your Form in XML Source Mode

If you need to change a property that Designer doesn’t expose in one of it’s property editors, then change the property via script.  For example: Designer doesn’t support making a positioned subform repeatable.  Rather than adding an <occur> element in XML source, set this property in script:

Subform1.occur.max = "2";
var vNewSubform = _Subform1.addInstance();

Batch Changes to your Form

For advanced users — if you need to make global changes to the contents of your form, this blog entry shows how a form author can write JavaScript to modify their template in Designer.  Likely a bit easier than writing XSLT.

Use FormCalc Functions — from JavaScript

FormCalc has some built-in functions that give access to some powerful functionality.  There is a way to bridge between JavaScript and FormCalc in order to use these functions.  Look here.

June 16, 2009 update

Use Strict JavaScript

Run lint against your JavaScript.  Choose options that make it as strict as possible.  Details here.