Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Home

Designer 8.0 Now Shipping!

That’s right! The day has finally come. At the moment, Designer 8.0 is only shipping with Acrobat 8.0 Professional. You can download the trial to check it out.

Jeff Stanier, our product manager, has put together a great document detailing what’s new in Designer 8.0. This is a really nice upgrade with lots of really nice brand new features like an integrated spell checker, greatly improved PDF Form importing (as "artwork"), improved digital signature support, test data generation, ability to show all scripts in a container, support for transparency in PNG and GIF image files and much, much more including some nice little usability improvements to make it easier to work with your forms.

In the coming weeks, I’ll be giving more details on these features and I’ll also be transitioning to Designer 8.0 and Acrobat 8.0 for future tutorials, targeting Designer 7.x/Acrobat 7.x only where appropriate.

One of the nice things about Designer 8.0 is that it now supports side-by-side installations along with older versions, making it easy to have Designer 7.1 and Designer 8.0 on the same machine for comparison and testing.


Posted by Stefan Cameron on November 9th, 2006
Filed under Designer

oneOfChild Scripting Property

Sometimes it’s necessary to access the properties contained within a field object’s UI property. For example, you might want to highlight only the content area (the value portion as opposed to the caption portion) of a text field. The problem with doing that is that you need to access the UI property’s one-of property in order to get at the Border object that it contains. The "ui.{one-of property}.border" object controls the appearance of the field’s content area. (Tip: It’s also the object that’s affected when you use the Appearance property on the Field tab in the Object palette).

If you were to look at the XFA specification supported by Designer 7.1, you would find, on page 664, that the UI element contains various one-of properties (which describe a set of properties from which only one may be specified at any given time) which vary depending on the type of field you’ve created on your form. For example, if it’s a text field, it has a

field.ui.#textField

property whereas a drop down list would have a

field.ui.#choiceList

property.

Based on the various definitions of XFA fields, you would have to write the following script to change a text field‘s content area color (shown here in FormCalc):

$.ui.#textField.border.fill.color = "255,0,0"

But what about a drop down list? Because it uses a different UI one-of property ("choiceList" instead of "textField"), you would have to write the following script (shown here in JavaScript) to change its content area color:

this.ui.resolveNode("#choiceList").border.fill.color.value = "255,0,0"

This is all fine as long as you know the type of object on which the script will be executed but what if you wanted to change the content area color of all fields on your form? You might decide to define multiple arrays that contain references to text fields, numeric fields, etc. (one array for each type) but that wouldn’t be very practical because you would have to remember to keep that list up-to-date for every change you made to your form.

A much easier way to do this is simply by using the oneOfChild scripting property: It’s designed to return a reference to the one-of property that has been specified in the Object Model on the object on which it is used. In other words, if you used it on a text field‘s UI property, it would represent the "#textField" property whereas on a drop down list, it would represent the "#choiceList" property.

If we put this in practice, it means you could use the following script to change the content area color of any field object you find on your form (shown here in FormCalc):

FieldObject.ui.oneOfChild.border.fill.color = "255,0,0"

where "FieldObject" would be a variable holding a reference to a field object on your form.

Of course, the use of the oneOfChild property also works because the Border property is common to all UI one-of properties. There are some cases where some properties are specific to a certain "UI type" (like the "#choiceList.textEntry" property). In those cases, you may need to verify that you are, in fact, attempting to access those properties on the right kind of UI one-of property or else you’ll get a scripting runtime exception.


Posted by Stefan Cameron on November 9th, 2006
Filed under Scripting

Bug: Unable to Set Caption or Value Font Separately

Description

I was showing someone how to use Designer 7.0 today and came across a bug in the Font palette. I was trying to show them how to make the caption of a text field bold without making the value bold using the Bold (“B”) button on the Font palette however I could only change both the caption and value fonts together, not separately as one should be able to do using the selector control located at the top of the palette (which reads, “Currently editing Caption and Value…” by default).

Using the selector control, you should be able to set it to “Currently editing Caption properties…”, press the bold button and make only the caption font bold. Unfortunately, that’s not what happens. Instead, both fonts (or, the entire field) is changed to bold.

Rest assured, this bug was immediately fixed in Designer 7.1 — a highly-recommended upgrade because tables were introduced in that version, amongst other things.

Workaround

The good news is that there’s a simple workaround using script. All you need to do is use the Font palette to make sure that the Bold button isn’t activated (that the field isn’t bolded) and then set the following FormCalc script statements on field’s Initialize event using the Script Editor palette:

$.caption.font.typeface = "Myriad Pro"
$.caption.font.weight = "bold"
$.caption.font.size = "10pt"

Feel free to specify a different font name or point size if you like although I would recommend using the same font name and point size as you specified in the Font palette so that the result doesn’t differ too much from what you see on the canvas.

Finally, preview the form as PDF using the canvas’s PDF Preview tab. When the form is initialized (loaded) in Acrobat, the field’s caption font will be set to the type, weight and size you specified.

Fix

Please refer to the Bug List for updated information on the version(s) affected by this bug as well as if and when it was/will be fixed.


Posted by Stefan Cameron on November 3rd, 2006
Filed under Bugs,Designer

Expanding to Fit the Entire Value

A while ago, I posted an article detailing a trick to make the value of a field be displayed entirely within the field’s content area. Essentially, by setting the value font size to zero, this tells Acrobat to shrink the field’s content area (value) font at will to make the entire value entered fit horizontally. This can certainly be useful but there’s one significant drawback: the value font may shrink such that it becomes too small for anyone to read depending on how much data the user enters into the field.

Fortunately, there’s an alternative method to making a value fit within a field’s content area when you don’t know how long the value will be: Making the field’s width and/or height expandable!

The advantage of this solution is that the value font’s size remains constant (the same as which you specified it to be when you designed the form). When a field is made expandable, its "w" (width) and/or "h" (height) attributes are replaced by "minW" (minimum width) and/or "minH" (minimum height) attributes, respectively. These attributes define the initial and minimum size of the entire field (that is, its caption and content areas combined). When the width is extended, however, only the field’s content area is increased in width. Its caption area remains the same width. On the other hand, causing the height of a field’s content area to be extended will also cause the caption area’s height to be extended.

Making a Field Expandable

Specifying that a field’s width and/or height is to expand to fit its content is quite simple: You just need to check the "Expand to fit" check box that pertains to the width and/or height property on the Layout palette.

Getting a Tight Fit

So far, you’ve learned how to make a field’s width and/or height expandable, essentially by specify a minimum width and/or height instead of a set width and/or height. Now what if you wanted to ensure that the field’s width and/or height was always just wide enough to contain whatever value was entered? For example, you don’t want a whole bunch of empty space if you set a minimum width of 2 inches to have a nice initial size to enter a value into the field but the user only entered a value that required 1 inch to be entirely displayed.

In that case, you could simply set the minimum width to zero when the user leaves the field, if they’ve entered a value. This is done by scripting the field’s Exit event (shown here in FormCalc):

$.minW = "0"

Look-out for Long Values!

One thing you have to look-out for is extra long values — especially if you haven’t specified a maximum length for the field. If the user enters too much data, the field might simply run off the page.

If you don’t want to set a maximum data length for the field but you don’t want it to expand beyond a certain width, you can set a maximum width and/or height. Since Designer’s UI doesn’t let you set this property directly, you can use the field’s Initialize script to set it (shown here in JavaScript):

this.maxW = "4.5in"; // max width of 4.5 inches

Note, however, that if the user enters more data than can fit within the specified maximum dimensions, the value will be cut-off and won’t print so you may consider setting a maximum data length or resorting to the previous solution (setting the font size to zero).

Sample

This sample form implements the solution I’ve described in this post.

Download Sample [pdf]

Minimum Requirements: Designer 7.x, Acrobat 7.x.


Posted by Stefan Cameron on October 31st, 2006
Filed under Scripting,Tutorials

Scripting Table Columns

A few days ago, Sergio, one of my regular commenters, posted a question about programmatically adding new columns to a table. My reply to his comment quickly turned into something that I thought should be promoted to a blog post so here it is.

This question required some investigation because it led me to the discovery of a bug related to adding/removing instances of a table column in a form viewed in a version of Acrobat prior to 8.0. More on that later in this post.

The short answer to Sergio’s question is that yes, in fact, you can modify the set of columns in a table programmatically at runtime. You can do this by either using the presence attribute — although this isn’t recommended because it can lead to data merging problems — or you can use Instance Managers to do it, which is the recommended method to use.

Here’s a sample form that contains a table with a “repeatable column”. Using the add and remove buttons that are provided, you can add and remove instances of the 3rd column.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Table Structure

To better understand what’s going on here, I’ll start by explaining how tables are represented in XFA. In reality, there are no <table>, <tr> or <td> elements in XFA. What happens is that <subform layout=”table|row”> elements get used. When a subform represents a table, it’s layout attribute is set to table and when it represents a row, it’s set to row.

Table Subforms

If you read about using a subform’s Instance Manager in order to add/remove instances, you should know that a subform only becomes dynamic or repeatable once it’s placed in a flowed container and its set as repeatable using the Object palette’s Binding tab. By default, a <subform layout=”table”> element is flowed from top to bottom. Since the table subform contains row subforms which, in turn contain the cells, that means that every row in a table could easily be set as repeatable and then get an Instance Manager that you could use to add/remove instances of a particular row.

Row Subforms

Just like the table subform, a <subform layout=”row”> is flowed. Its flow direction, however, isn’t top to bottom, it’s right to left. This means that its contents — the cells — are flowed.

Cells and Columns

Table cells are little different. Essentially, since they reside in a row subform which is flowed from right to left, there’s no specific definition for what is a table cell. It’s simply any type of object (text, numeric field, subform, button, etc.) that’s placed within a row subform. The number of objects in the row determines the number of columns there are. Therefore, to have a 3×3 table, you would need 3 row subforms each containing 3 objects.

There’s no actual definition for a table column either. Table columns are inferred by the cells (put simply, without going into details about column spanning). This means that a column consists of objects in separate row subforms which are above and below each other (e.g. the first object on every row make-up the first column in a table).

Adding/Removing Columns

Given the explanations in my little “table primer” above, we now know that table cells are objects which are flowed from right to left within row subforms. Since row subforms are flowed by nature, it means that if a cell were a subform itself, it could be made repeatable and it would then get its own Instance Manager for free! And once we have Instance Managers, we can start adding and removing instances of those cells.

So the trick here lies in converting every cell which constitutes a column into a subform which then contains the type of object you would normally use to display information in that cell (e.g. a text field, a check box, etc.).

Now if you’ve never noticed the Type property on the Field tab in the Object palette before, you’ll want to check it out because it’s about to come in real handy for setting-up a dynamic table column which consists of cells which are all subforms. This property is used to change the type of the selected object(s). For instance, if you put a text field on a form and decide that it should have been a numeric field, you can change it’s type from text field to numeric field simply by using this property. Typically, you cannot change anything into a subform but when you select a table cell which is a text object (the default cell object type when you insert a new table into a form using the Insert Table menu command or the Table object in the Library’s Standard tab), you can, in fact, change it into a subform. So just select each cell in the column and change its type to a subform using this property. The result will be a cell which is a subform that contains a text object. Then you can change the text object into some other field type which better represents the data which will go into the cell.

Making Cell Subforms Repeatable

Unfortunately, this is one case where you’ll have to use the XML Source tab because the repeatable property isn’t available for cell subforms on the Object palette’s Binding tab. Since it’s a valid XFA setting, you can set this yourself using the XML Source.

Switch to the XML Source window by selecting “XML Source” from the top-level View menu. Then, insert the following XML inside each subform which defines a cell:

<occur max="-1"/>

This means that the cell subform goes from looking like this:

<subform layout="tb" name="Col3SF">
  <field name="Cell3" w="29.9999mm" h="10mm">

to looking like this:

<subform layout="tb" name="Col3SF">
  <occur max="-1"/>
  <field name="Cell3" w="29.9999mm" h="10mm">

and signifies that the cell will have one initial and minimum instance and can have as many additional instances as you need (no maximum).

Last but not least, the script!

After all that, the script is actually quite straight-forward: To add an instance of a column just add an instance of every repeatable subform cell that constitute a column. In my sample, I have a 3×3 table and each subform cell is named “Col3SF”. That means that the script looks like this (in JavaScript):

Table1.HeaderRow._Col3SF.addInstance(0);
Table1.Row1._Col3SF.addInstance(0);
Table1.Row2._Col3SF.addInstance(0);
Table1.Row3._Col3SF.addInstance(0);

Then, to remove an instance of the column, just do the reverse: Use the Instance Manager’s removeInstance method to remove an instance of each cell subform.

Bug when adding/removing table cell instances

Of course, everything was going great until now… Unfortunately, I discovered a little snag in playing with table column instances while making this sample. Fortunately, the bug has already been fixed in Acrobat 8.

Description

The first manifests itself when the second new instance of a column is added (by adding an instance of a column, I mean adding an instance of each cell subform in each row which collectively constitute a table column — as in my sample script above earlier). As of the second new instance, the cell in the header row will stop appearing in all subsequent instances.

There’s also an issue with removing column instances (by removing an instance of each cell subform). In this case, all new instances are removed until what was originally the first instance to be added is removed, leaving only the original, initial instance. What happens is that part of the last instance to be removed remains rendered on the form which doesn’t really look nice because it looks like the instance is still there (even though you can’t click on the cells anymore).

The problem is that the form’s layout isn’t properly updated after columns are added or removed.

Workaround

Luckily, there’s the xfa.layout object which gives us a solution to this problem when version of Acrobat prior to 8.0 are used to render the form. More specifically, versions 7.0.5+ since table support didn’t appear until then, when Designer 7.1 was released.

Using the xfa.layout object, you can tell Acrobat to re-render the form at your command. This effectively repaints the entire form and gets rid of any artifacts (those being the incorrectly rendered column instances). So, after adding or removing column instances, just place the following command:

xfa.layout.relayout();

Please use this with caution, however, since it may adversely affect the performance of your form (since this statement will essentially cause the entire form to be re-rendered every time a column is added/removed). That’s why I check the version of Acrobat that’s rendering the form in my sample so that I know whether I need to apply the workaround or not.

The other workaround is simply to use Acrobat 8.0 to render the form (save is as an “Acrobat 7.0.5 Dynamic PDF Form” but open it in Acrobat 8.0). Acrobat 8.0 now properly renders all instances as they get added or removed.

Fix

Please refer to the Bug List for updated information on the version(s) affected by this bug as well as if and when it was/will be fixed.


Posted by Stefan Cameron on October 28th, 2006
Filed under Acrobat,Bugs,Instance Manager,Scripting,Tables,Tutorials