Form Variables

In the sample from my previous post I introduced an integer form variable without drawing attention to it.  In this post I will describe form variables in much more detail.

Creating Variables in Designer

In order to create a form variable from Designer, you choose file/form properties/variables.  In this screen shot there are two variables: "foo" and "bar". 

FormProperties

The resulting XFA markup looks like:

<template>
  
<subform>
      <variables>
         <text name="foo">123</text>
         <text name="bar">abc</text>
      </variables>
   </subform>
</template>

There are some limitations to Designer support for variables:

  • Creates only <text> variables
  • Cannot create a variable with an initial value that is empty
  • Places variables under the root subform only

Creating Variables in Script

In a previous post I described the code for creating a form variable in JavaScript.

var vNewVar = xfa.form.createNode("text", "vMyVar");
vNewVar = "abc";
ExclusionGroup.variables.nodes.append(vNewVar);

The first parameter to createNode() can be any of the XFA content types.  The set that you would likely find useful in a scripting context are: <boolean>, <decimal>, <float>, <integer>, <text>.  You can create other types such as <date>, but a <date> behaves like a <text> (a string) because there is no date data type in JavaScript.

Typed variables

The .value property on a variable is a variant.  It returns a typed value based on the content type.  It will return string for <text> , it will return number for <integer>, <decimal> and <float> and returns boolean for <boolean>

Typed variables have the advantage that script operations that use them will do the right thing.  e.g. if you define two <text> variables: v1.value="3"; v2.value="5", then the expression "v1.value + v2.value" will return "35".  If they are defined as <integer>, the result of the expression is "8".

Use any Subform

The <variables> element may appear under any subform.  It often makes sense to create the variable in the context where it is used e.g. in the case where it is used within a repeating subform or a fragment.

Hidden from the Designer

When you define script objects that use variables, it can be inconvenient to create the form variables from the Designer UI.  If you do, your script then has an external dependency, and other people modifying the form can muck with your variables.  It really only makes sense to create them from Designer if they truly have global scope.  Of course, defining them in Designer does have the advantage that they show up in object assist.

Form State

Anatole Matveief wrote a nice form state tutorial on Stefan Cameron’s blog.  As of Acrobat 9, form variables are stored as part of the preserved form state i.e. after save/close/open, any form variables will be restored.  This can be a very valuable feature, but can also require some caution — when creating a new variable, you should first check for its existence.  If not, you may end up with multiple copies of the variable.  The existence check looks like:

if (mySubform.variables.nodes.namedItem("vMyVar") == null)
{
   
var vNewVariable = xfa.form.createNode("integer", "vMyVar");
    vNewVariable.value = 42;

    mySubform.variables.nodes.append(vNewVariable);
}

Dependency Tracking

Unfortunately, variables do no participate in dependency tracking.  If you define a calculation that uses a variable, the calculation will not re-fire automatically when the value of the variable changes.

What about Fields?

It is really convenient to be able to define variables in the context of a subform, but what about the case where your context is a field?  The good news is that there are two places where we can place content elements within a field: <desc> and <extras>.  For example, to create content under a field you can code:

if (myField.desc.nodes.namedItem("vFortyTwo") == null)
{
   
var vNewVariable = xfa.form.createNode("integer", "vFortyTwo");
    vNewVariable.value = 42;

    myField.desc.nodes.append(vNewVariable);
}

The content can then be referenced in script as: "myField.desc.vFortyTwo.value". 

Sample

I have added a sample that has code to demonstrate creating and referencing form variables and content elements under a field <desc> element.  The script lives under the "Create Variables" button.

6 Responses to Form Variables

  1. Duarte Cunha Leão says:

    If one just needs to store temporary information, related to a field or form, or whatever xfa object, one can create an “expando” property on it.There you can store all JavaScript possible types:xfa.form.MyField.__CACHE__ = {A: 123,B: “123”,C: new RegExp(“123”)};Of course, it all only exists as long as the related document.

  2. Duarte:I’m glad you raised this issue. As it turns out, there are problems with this approach. It’s a bit much to describe in a comment — I’ll start a new blog entry to go into the details.thanks,John

  3. Duane says:

    Hi John,I’ve been using xfa.form.createNode and extras.nodes.append to create object holders for various properties which I want to persist for objects on my form.This has been working well through the development cycle, but as we prepare for rollout and test – it turns out that by creating nodes within JavaScript, it seems to invalidate the Reader Extension usage rights and if I save and re-open the form, I get the infamous message “This document enabled extended features in Adobe Reader. The document has been changed since it was created and use of extended features is no longer available.”Have you found a way to maintain usage rights while persisting dynamically created object properties?thanks- Duane

  4. Duane:As we’ve discussed offline, storing extras or using form state shouldn’t interfere with Reader Extensions. Sounds like there may have been other factors involved.John

  5. Duane says:

    Thanks a bunch for the sample John.It appears to be an issue with Reader 8. When a property has been set to a value which was defined in a node (like an extras node) which no longer exists after a file->save … it invalidates teh usage rights.Cheers- Duane

  6. John Brinkman says:

    Duane:I’ve passed your comment along to our software verification group.thanks,John