Posts in Category "Uncategorized"

Script Dependencies and "recalculate()"

For older versions of Acrobat, there were a lot of forms which would call xfa.form.recalculate() in various places.  This was to ensure that fields will get updated which depend on other fields that may have changed.  Newer versions of Acrobat (8.1 and higher) are designed to not require so many calls to recalculate(), because the system is smart enough to evaluate your calculate script and figure out what fields it depends on.  The system puts "listeners" on those other fields so that whenever they change, my calculate script gets called automatically.  I don’t have to declare the dependency.

For example, I have a Total field that calculates its value from several other fields (Field1, Field2, Field3).   Any time Field2 changes (due to either a calculation or to the user typing something in Field2), the Total calculate script will be called automatically.

But now make this dynamic:  add a repeating subform with Add and Remove buttons so the user can create new instances of the subform.  For example, I have a repeating subform containing a Weight field.  Outside the repeating subform, a Total field has a calculate script which sums up all the instances of that Weight field.  Pretty simple.  

clip_image001

But the listeners aren’t correctly added when a new subform instance is created.  My Totals field is listening to the first instance of RepeatingSubform[0].Weight, but when RepeatingSubform [1] is created, Totals isn’t listening to changes to RepeatingSubform [1].Weight.  Stefan Cameron talks about this in an older blog post:  http://forms.stefcameron.com/2006/05/20/add-recalculate/

Interestingly, look at the calculate script on Total:

var sum = 0;

var columnArray = xfa.resolveNodes( "RepeatingSubform1[*].Weight1");

for( var i = 0; i<columnArray.length; i++)

{

    sum += columnArray.item(i).rawValue;

}

this.rawValue = sum;

The call to xfa.resolveNodes() happens to cause the listeners to be updated!  This leads to very odd behavior:  if I change RepeatingSubform [1].Weight, it won’t update Totals, until I change RepeatingSubform[0].Weight.  Then any additional Weight field changes will cause Total to update correctly!

So if I start with one weight field (W0) and add 3 more, I end up with weight fields like this:

                W0 (RepeatingSubform[0].Weight)

                W1

                W2

                W3

                Total

Then changes to the added ones (W1, W2, W3) won’t update the Total – yet.  Changing W0 will update the total, and once you do that, now changes to W1, W2,W3 will work!

Then if I add a W4:

                W0

                W1

                W2

                W3

                W4

                Total

Now changes to W0, W1, W2, W3 will all continue to work but my newly-added W4 won’t work (until I change one of W0-W3).

Workaround:

Add script to the indexChange event of RepeatingSubform, which will take care of all newly-added instances; Totals will be recalculated and will now be "listening to" the new instances.  This is more efficient than calling recalculate() on the entire form – it just recalculates that particular field or subform.

Total.execCalculate();   // Note: you can call this on a subform too:  TotalsSubform.execCalculate();

Add the same script to the delete button click() event so that the Total is recalculated when an instance is deleted.  The important part of that code is:

TotalsSubform.execCalculate();  // this avoids having to call the entire form’s recalculate() method.

oTargetSubform.instanceManager.removeInstance(oTargetSubform.index);

Continue reading…

A Shortcut for Inserting SOM Expressions into your Script

The XFA scripting model can be a bit… overwhelming… sometimes.  It can be hard to figure out what SOM expression you need need to use.  But there is an alternative to typing out a long, many-layered-SOM-expression.  While typing in the script editor, if you hold down the CTRL key and click on an object on the canvas, the object’s SOM expression will be inserted into your script.  The SOM expression will be relative to the object hosting the script. 

If you want the absolute SOM, then hold down CTRL+SHIFT and click on the object.

Please note that this trick only works when clicking on objects on the canvas, not in the hierarchy dialog.

xfa.host.setFocus()

Did you know that starting with version 8.1, the setFocus() method can accept either a SOM expression or a node object?

For example,

xfa.host.setFocus(this);

xfa.host.setFocus(this.somExpression);