Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Home

Add, Recalculate

Here’s a little something that very important to know when working with dynamic subforms and using their Instance Managers (IMs) to add instances of them to a form: New subform instances aren’t automatically incorporated into the form’s calculations!

You would immediately notice this problem if you had a form which calculated a total based on line items which can be added or removed from the form. When you add a new line item using the IM’s addInstance(bool) method, the grand total of, say, the cost of all line items isn’t updated to reflect the data you enter into the new line item. This is because the new line item hasn’t been made part of the form’s set of calculation dependencies and is therefore not accounted for by your “grand total” calculation. As a matter of fact, until a call to xfa.form.recalculate() is made, none of the new instances added will be included in the form’s calculations.

To demonstrate this, I’ve created a sample form which has a “line item” section to which line items can be added. As line items are added and their costs changed, the grand total fields at the bottom calculate the total cost of the order: One grand total field performs its calculation using the FormCalc SUM function and a SOM Expression identifying the collection of fields to total while the other uses the LineItem dynamic subform’s IM object to calculate the grand total. Finally, there’s a check box at the top of the repeating “line item” section which, when checked, will cause the “Add Item” button to execute the xfa.form.recalculate(true) statement after adding a new line item. To see the difference, play around with the form by adding line items with the check box both checked and unchecked.

Note that this issue was addressed in Acrobat/Reader 8.0. Therefore, if your form targets this version (or later) of Acrobat/Reader, you shouldn’t need the recalculate() workaround.

Download Sample [zip]

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

Updated Nov 19, 2009 — Added note about the issue being resolved in Acrobat/Reader 8.0+.


Posted by Stefan Cameron on May 20th, 2006
Filed under Instance Manager,Scripting,Tutorials

BFMA, Phoenix, 2006

I’m very excited to be attending the BFMA’s 37th International Symposium on Forms and Business Processes this coming week in Phoenix, AZ.

Adobe is one of many sponsors for the event. It’s going to be a very exciting time for all of us!

If you have any questions about how to do stuff in Designer as well as some of the things you’d like to see in future releases, don’t be shy! I’m always trying to find new ways to make our product better and I’d love to meet you and get some feedback on what you like and what you don’t like.


Posted by Stefan Cameron on May 20th, 2006
Filed under BFMA Symposium,Conferences

Is that Field Empty?

As a form designer, you can be almost certain that there will be a time when you’ll need to check a field to see whether its value is empty (whether the form filler has specified a value).

For longest time, I had been doing it like this in JavaScript:

if (theField.rawValue == null || theField.rawValue.length == 0)
  // field is empty
else
  // field has been filled

That served me quite well until yesterday when I found myself needing to do the same, but this time in FormCalc. Theoretically, the following should’ve worked:

if (theField == null | theField == "") then
  // field is empty
else
  // field has been filled
endif

But for some reason, the FormCalc interpreter was giving me a hard time with the null keyword (maybe it’s because I don’t use it very often and it was upset at me, I don’t know — if you’re a developer, you’ll understand that sometimes, code can have feelings and a mind of its own 😉 ) so was forced to try and find some other way to check if a field’s value is null in FormCalc and I found one:

theField.isNull

The isNull property (of the XFA Scripting Model’s node object) “indicates whether the current data value is the null value”, as stated on page 422 of the Adobe XML Form Object Model Reference (located in the XML section).

This means that the following JavaScript expression checks whether a field’s value is empty:

(theField.isNull || theField.rawValue.length == 0)

And in FormCalc:

(theField.isNull | theField == "")

Posted by Stefan Cameron on May 19th, 2006
Filed under Scripting

Instantiating Subforms at Runtime

Something that’s often desired, when working with dynamic forms, is to let the user specify, at run time (in Acrobat), how many lines of information are required to specify what they want.

The classic example is a Purchase Order form on which there are objects (usually buttons) which let you add and remove item lines from the section of the form which calculates the total cost of the order based on how many items are being ordered and the quantity and cost of each item.

In order to achieve this, the use of the Instance Manager is required. The Instance Manager is an object which exists only on repeatable subforms (this could be a subform which is parented to a flowed subform and set to repeat for each data item or it could be a row in a table — since rows and tables are, essentially, subforms). With this special object, you can modify the set of instances of a repeatable (dynamic) subform.

You can access the Instance Manager in two ways. The first is by accessing the object from the dynamic (repeatable) subform:

// append a new instance of DynSubform within its parent container
DynSubform.instanceManager.addInstance(true);

// ensure that the new instance is included in
//  subsequent calculations
xfa.form.recalculate(true);

The second is by using the shortcut “underscore” syntax (note that this syntax is supported if the form is rendered to PDF):

// remove the third instance (zero-based) of DynSubform
_DynSubform.removeInstance(2);

// work-around for Acrobat 7.x bug (reported) where number of
//  instances isn't properly updated after calling removeInstance
xfa.form.remerge();

The drawback to using the first syntax is that there must always be at least one instance of the dynamic subform which exists. If you have a form which must initially not have any instances of a particular dynamic subform, then you need to use the second syntax with the underscore since that special object is always “available” to you regardless of the current number of instances of the dynamic subform in question.

It’s also important to pay special attention to the minimum, maximum and initial number of instances of a dynamic subform. This is set on the Object palette’s Binding tab once you’ve specified that the subform is to Repeat for Each Data Item. The min and max limits must be repected at all times when using the Instance Manager. For example, if you set a min count of 1 and attempt to remove the last instance of a dynamic subform, an exception will be thrown which will result in a script error. You can check the current number of instances by using the Instance Manager’s count property and compare it to, for example,

// get the minimum number of instances that can be instantiated
_DynSubform.min

There are other things you can do with the Instance Manager such as setting the number of instances (using its setInstance(int) method), move instances around (using its moveInstance(int, int) method) etc. These are covered in detail in the Adobe XML Form Object Model Reference (located in the XML section). Check-out the Manipulating instances of a subform section on page 675.


Posted by Stefan Cameron on May 18th, 2006
Filed under Instance Manager,Scripting

Calculate Scripts

I just learned something very interesting while answering a forum thread just now which I thought I should share with the rest of you.

In all the scripts I’ve written so far, I had never realized this simple rule: When writing calculation scripts to set the value of certain fields, the line in your script which assigns a value to the field on which the Calculate event was fired should always be the last line in your script. This is because the last-executed line in your script is the one that the XFA Object Model will use to determine the value of that field.

While it’s generally not recommended to do much more than set a field’s value in the Calculate event, reality is that most of us use it for much more than that: Since it fires on all fields on a form after a field’s value changes, we may use it to affect the presence, color, dimension, etc., of some fields which depend on the values of other fields. Therefore, it’s very easy to fall into this trap where your calculation script isn’t working probably simply because you haven’t structured it correctly.

Take the following FormCalc script as an example:

if (NumericField1 > 0) then
	NumericField1 * 10;
	$.presence = "visible";
else
	0;
	$.presence = "invisible";
endif

This scripts runs in the Calculate event of a numeric field and, if NumericField1’s value is greater than zero (0), results in the field becoming visible and its value set to the product of NumericField1’s value multiplied by 10. If NumericField1’s value is zero (0) or less, its value is set to zero (0) and it becomes invisible. Note the order of the lines which set the field’s value and the ones which set its presence: The value is set before the presence is set.

The result of this script is that the presence is affected properly depending on the value of NumericField1 however, since the last-executed line is “$.presence = ‘visible’” (or “invisible”), the value acutally assigned to the field is “visible” (or “invisible”) which evaluates to “0” as a numerical value. Therefore, with this script, the value of the product field would always be zero (0).

If you change the order of the lines which set the field’s value and presence as follows:

if (NumericField1 > 0) then
	$.presence = "visible";
	NumericField1 * 10;
else
	$.presence = "invisible";
	0;
endif

Then both the field’s presence and value will be set correctly because the last-executed lines in each block are the ones which set the field’s calculated value.


Posted by Stefan Cameron on May 15th, 2006
Filed under Events,Scripting