Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

AcroForm Field Name Generator

So you’ve read my previous post about AcroForm Objects and now you’re wondering what you do with that stuff. Those more adventurous might even have tried to use the event.target.getField method to do something cool.

If you’re going to do things on the application or the document without attempting to affect a specific field, it’s pretty straight-forward: You just call methods on the app (Acrobat Application) or event.target (Acrobat Document) objects. Getting an AcroForm Field object, however, isn’t as simple as you may think because of the naming conventions used when the Acrobat Form objects are created, based on the XFA Form objects.

Let’s say you have a field, named “MyField”, parented to the second page, named “Page2”, of your form, named “form1”. For some reason, you need to access that field’s pertaining AcroForm Field object. If you tried

event.target.getField("MyField")

you wouldn’t get very far because the actual name of the field is:

form1[0].Page2[0].MyField[0]

Basically, each AcroForm Field object is named with a verbose form of the XFA SOM Expression of its pertaining XFA Form object (also known as a Fully-Qualified SOM Expression).

To help with generating the correct AcroForm Field name for a given XFA Form object, I thought I would write a little bit of script which outputs the Fully-Qualified SOM Expression (which is the AcroForm Field name) for a given XFA Form object:

// Returns the fully-qualified name for the specified object.
//  This means the name always specifies the index.
//  Therefore, if the name is specified, it's "name[index]".
//  If the name isn't specified, it's "#className[index]".
function GetVerboseFieldName(oNode)
{
  // Unnamed nodes have default names which their class name
  //  ("subform", "field", etc.) with a "#" prefix.
  //  Unfortunately, oNode.name won't return this if the node
  //  doesn't have a specific name. It'll just return an empty
  //  string. Also, oNode.index will be undefined. If it weren't
  //  for oNode.index being undefined in this case, we could've
  //  done something like
  //  SOM = "#" + oNode.className + "[" + oNode.index + "]"

  //  but we'll have to use the somExpression property instead
  //  and extract the name out of it because this will return
  //  the "#" name with the correct index.
  // Since somExpression returns the name and index for the
  //  object in all cases (whether the name is specified or
  //  not), we can use the following syntax in all cases:

  var nPos = oNode.somExpression.lastIndexOf(".");

  // If the field has a name, check to see if it has any periods in its name.
  // If that's the case, they'll be escaped with backslashes and we need to
  //  look for another period.
  if (oNode.name != null && oNode.name.length > 0)
  {
    while (nPos > 0)
    {
      if (oNode.somExpression.charAt(nPos - 1) == "\\\\")
      {
        // we found an escaped period, keep looking
        nPos = oNode.somExpression.lastIndexOf(".", nPos - 1);
      }
      else
      {
        // stop looking since we have an unescaped period
        break;
      }
    }
  }

  if (nPos >= 0)
  {
    // get everything after the last "." to the end
    return oNode.somExpression.substr(nPos + 1);
  }
  else
  {
    // in this case, the SOM expression is a single name (unlikely
    //  but theoretically possible)
    return oNode.somExpression;
  }
}

// Returns the Fully-Qualified SOM Expression for the specified field.
function GetFQSOMExp(oField)
{
  var sFQFieldName = GetVerboseFieldName(oField);
  var oParentNode = oField.parent;

  // The absolute root of the XFA Object Model is the xfa object
  //  which contains a single form object, which then contains
  //  what the Hierarchy palette shows as being the "root
  //  subform" ("form1" by default). So we stop when we reach
  //  xfa.form.
  while (oParentNode != xfa.form)
  {
    sFQFieldName = GetVerboseFieldName(oParentNode) +
      "." + sFQFieldName;
    oParentNode = oParentNode.parent;
  }

  return sFQFieldName;
}

You can now take this code and either place it directly inside the event in which you need an XFA Form object’s pertaining AcroForm Field name and call it directly or you can place it in a form-wide Script Object where you can access the code from anywhere.

With this code, changing an XFA Button object’s highlight property such that it gets an outline rectangle when clicked (as opposed to the default which is an inverted fill color) is as easy as this (in JavaScript in the button’s Enter event, assuming you’ve placed the above code directly inside the Enter event):

event.target.getField(GetFQSOMExp(this)).highlight =
  highlight.o;

Beautiful? I think so. Get the Acrobat JavaScript Scripting Reference and go crazy! Just remember: This functionality is only available when your form is loaded in Acrobat.

Updated: February 14, 2007 — Added support for objects with periods in their names.


Posted by Stefan Cameron on June 14th, 2006
Filed under AcroForm Objects,Scripting
Both comments and pings are currently closed.

4 Responses to “AcroForm Field Name Generator”

  1. High Frequency Generator on June 20th, 2008

    Thx a lot for this script. I’m having a few problems with it but I think I can get help from one of my friends but other then that thx a bunch

  2. Stefan Cameron on June 25th, 2008

    High Frequency Generator,

    Good to hear! I’m glad you found it useful.

  3. Bruce on September 8th, 2008

    Thanks Stefan for you posts they have been a great help. I was hoping you would be able to explain some more of the SOM expressions. I have a form that contains script using the field.somExpression scripting property. Sometimes the som expression returned starts ‘xfa[0].form[0]‘ and sometimes ‘xfa[0].form[1]‘ this would make me think there is a second form dom created. Is this possible?

  4. Stefan Cameron on September 12th, 2008

    Bruce,

    As far as I know, it’s not possible to have a second Form DOM. There should only ever be a single Form DOM per form.