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.