Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

AcroForm Objects

Today I thought I would tackle the subject of AcroForm Objects — objects available via scripting in the Acrobat Form Object Model — because they offer unique possibilities for your forms when they’re running in Acrobat in the PDF format.

Just to be clear, AcroForms are specific to Acrobat and therefore this functionality doesn’t apply when rendering your forms to a target other than PDF (e.g. when using LiveCycle Forms to render your XFA Forms as HTML).

First, let’s explain what XFA (XML Forms Architecture — a W3C Submission) does: It lets you describe a form, using a defined set of rules that govern an XML structure, which can target many different clients (e.g. PDF, HTML, etc.) — as long these clients support the XFA format. Today, the Adobe LiveCycle Designer targets PDF out-of-the-box and, along with LiveCycle Forms, targets HTML.

The fact that XFA is always translated into a format which can be understood by a client with which a user interacts in order to fill a form and possibly submit its data to a receiver means that the scripts you write in your XFA forms get executed in the target client application (such as Acrobat or a web browser). If the target client also contains a Scripting Object Model — like Acrobat does — there may be ways that you can take advantage of specific functionality exposed by the client which is hosting your XFA forms.

This brings us to the topic at hand: Acrobat’s Form (AcroForm) Object Scripting Model. If you’re designing your form only to target PDF (or you add code to your form to detect when your form is being hosted by Acrobat using xfa.host.name, for example), you can get access to the Acrobat app, Document and Field objects, amongst others, and do some really cool things like have a field with invalid data start flashing red when the user attempts to submit the form’s data.

xfa.host

When writing scripts in an XFA form, you have access to the special xfa.host object. This object gives you access to methods which are specific to the application hosting your form (such as Acrobat, a form server or a web browser). For example, the

xfa.host.name

property tells you the name of the application hosting your form at the time the script is interpreted. If your form is being viewed/hosted in Acrobat, this property will return “Acrobat” while it’ll return the name of the browser if it has been served to a web browser. Furthermore, it’ll return “Presentation Agent” if the script was flagged to run on the server and the server application serving the form to PDF or HTML is Adobe’s LiveCycle Forms product.

xfa.host also gives you access to other properties and functions such as

xfa.host.messageBox // displays a dialog box on the screen
xfa.host.validationsEnabled // turns the form's validations on/off with a single call

but take note that not all functions and properties are available on all hosts (e.g. since a server host can’t display a dialog which requires user input, the xfa.host.messageBox function is only supported on client hosts like Acrobat and web browsers).

You can obtain more information on xfa.host on page 185 of the Adobe XML Form Object Model Reference.

Acrobat app Object

Since the scripts you write in functions and events within an XFA form are interpreted by and executed within the context of Acrobat’s Scripting Engine, you have access to a special object called app. This object gives you access to the collection of active documents and plugins, amongst other things, and lets you display alert messages

app.alert("Hello world!");

and even set Acrobat into full screen mode with a red background!

app.fs.backgroundColor = color.red;
app.fs.isFullScreen = true;

Note that while color.red isn’t an object provided by the XFA Scripting Object Model, it still exists within the context of your scripts because the scripts are ultimately interpreted and executed within Acrobat. You can get more information on the app object in the Acrobat JavaScript Scripting Reference.

xfa.event

This is a special object which exists only via the XFA Plugin which executes XFA scripts on XFA object events inside Acrobat. Whenever an event occurs (such as the click of a button or a field gaining input focus), your script has access to the xfa.event object which gives lots of important information about the event.

For example, if you want to know the value that was selected in a list box or a drop down list in order to change the state of another object on your form, you would script against the list box’s or drop down list’s Change event. If you used the following code to get the value of the item that the user selected:

this.rawValue

you would get the previously-selected value because the object’s rawValue property isn’t updated until after the Change event has occurred. In order to get the information you need, you must use the following code:

xfa.event.newText

which will give you the value of the item the user just selected.

xfa.event also gives you access to a very useful property called target: In Acrobat, this property specifies the Acrobat Document object (which contains the Acrobat Field object which wraps the XFA object whose event is being scripted). This means that you can get at the Acrobat Document object for the “active document” just by using:

event.target

(Note that you don’t need — and shouldn’t use — the “xfa” prefix when accessing the “event.target” property — I don’t know why yet but you’ll have trouble using it if you use the “xfa.event.target” syntax.)

Using this information, you can:

event.target.zoom *= 2; // increase the zoom level two-fold
event.target.zoomType = zoomtype.fitW; // zoom to page-width level
event.target.zoomType = zoomtype.fitH; // zoom to page-height level

or you can use the getField method to get an Acrobat Field object and do some more interesting things.

You can get more information on the Document and Field objects in the Acrobat JavaScript Scripting Reference.

Putting it all Into Perspective

To tie this all together, I’ve drawn-up a simplified version of the Scripting Object Model the way I picture it in my head:

Scripting Object Model (simplified)

This image illustrates how things work from the perspective of a script running within an XFA Event or an XFA Script Object Function (note that you don’t have access to the xfa.event object there unless you pass it into the function by calling it from an XFA Event). You can see how, from the XFA object, you can get to the:

  • Acrobat app object (directly);
  • Acrobat Document object (via event.target or the app object);
  • Acrobat Field object (via the Document object);
  • xfa.host object (directly).

Hopefully this post will have given you a general idea of the Acrobat-specific tools at your disposal when you’re writing XFA scripts using the JavaScript language. Please note, however, that changes may occur to the way XFA Form Objects are hosted within Acrobat in future releases and therefore using the AcroForm Object Model should be a last resort if an XFA equivalent simply isn’t available.

Updated: August 30, 2006


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

35 Responses to “AcroForm Objects”

  1. Rob McDougall on June 12th, 2006

    Hi Stefan,

    Another great article! Just one quick correction. XFA was a W3C submission but is *not* a W3C standard. A standard is a document that has gone through a rigorous review process by multiple independent parties. A W3C submission is done unilaterally by a party or parties interested in having the W3C take the submission into consideration during the standards process.

    Just because something appears on the W3C site, doesn’t make it a W3C standard, but it does mean that the parties involved are participating in the W3C process.

    I should know because my name is on the submission. :)

    Regards,
    Rob

  2. Stefan Cameron on June 12th, 2006

    Rob,

    Thanks for correcting me on that one! I see now that the W3C document states that it’s a submission and not a standard. I’ve made the correction in my post.

  3. smvo on July 4th, 2006

    Hi,

    Thank you for your article.
    I would like to make one question that I think is related to this article:

    When opening a pdf file using a xdp file, I realize that at least some events get fired twice. Can you explian that?

    Thank you

  4. Stefan Cameron on July 4th, 2006

    smvo,

    Based on the Adobe ML Form Object Model Reference, opening a dynamic PDF form will result in the pre-render sequence of events to fire twice completely simply because of the way the form is loaded into Acrobat.

    Also, you’ll get multiple Initialize event triggers depending on whether you’re merging data into your form: If you don’t merge data, you should only get it once for every object; otherwise, you’ll get it once prior to data merge and another time after the data merge has completed.

    Does that clarify things for you?

  5. smvo on July 5th, 2006

    Stefan,

    I would like to make another question about a subject in your tutorial.

    You said this: “…your XFA forms get executed in the target client application (such as Acrobat or a web browser)”.

    My question is, how can I have a brwoser as a host/target application? I ask this, because, even when acrobat open inside a web browser, the host is still Acrobat, right?

    So How can I open a XFA form in a browser?

    Thank you again.

  6. Stefan Cameron on July 5th, 2006

    smvo,

    You can have your forms hosted by (executed within a) browser by deploying them to HTML via LiveCycle Forms — an Adobe LiveCycle solution which lets you securely capture data from and deploy your forms to a number of different devices from desktops to Pocket PCs without users having to install any extra software.

  7. smvo on July 17th, 2006

    Hello again Stefan,

    I have two more questions that I hope to be related with your topic. Any help is appreciated.

    1) When opening a xdp file referencing a PDF file, for instance in a browser IFrame, I realize the xdp file by itself opens inside the IFrame, and then it browses to the PDF and this way the PDF will no longer be opened inside the IFrame (so Im´not able to hide it from the user).

    Is there any way to control this beahaviour/event? For instance, is there any way to instruct acrobat to open the referencing xdp file in a predefined window´s frame? (self, top, etc)

    2) Because I couldn´t figured out a way to accomplish the previous goal, I tried to open a new hidden browser window where the pdf would be rendered, and automate the initialize event of the XFA PDF calling a button click event to print the document:
    xfa.host.print(0, “0″, (xfa.host.numPages -1).toString(), 0, 0, 0, 0, 0);

    The goal was to create a new hidden window, where the pdf would be rendered.
    This way the initialize event would be automatically call, and also the click event of a print button inside de pdf. The PDf would print and the browser window close.

    However there is one problem in this scenario: the print method of the xfa.host will be called, but it will soon stop sending to the printer. I can see the pdf being send to the printer spool at start but if the pdf is a bit longer the send to the spool will stop and the spool became clean without printing. It seems the print method is asynconous or something like this.

    Thank you

  8. Stefan Cameron on July 19th, 2006

    smvo,

    I’m afraid it’s “0 for 2″ in this case:

    1. The only thing I know of that you can do when opening a PDF is to tell it either to open in the current window or a new one — you can’t specify which frame it should open in.

    2. For security reasons, you can’t (or at least you shouldn’t be able to) silently (without user interaction) execute a print command neither by using xfa.host.print nor by using event.target.print. Therefore, attempting to execute a print command in an Initialize event shouldn’t result in anything.

  9. Sérgio on August 28th, 2006

    Hi Stefan,

    Here it goes 2 more questions about your article. Any help is really appreciate.

    I´m writing code in an application/folder level javascript file. From there, I would like to get the value of some fields palced in my XFA forms… Is this possible? At what level can we interact with xfa forms using application level javascript? For instace, can I pass an object as a function parameter to the application level javascript and then change some properties?

    Thank you!

  10. Stefan Cameron on August 30th, 2006

    Sergio,

    I don’t see why you couldn’t pass an XFA Object reference to an Acrobat application-level script. Also, from your script, if you get an Acrobat Document object, you can get the XFA Form Object Model from there by using the “xfa.form” object within the current context (the specific Acrobat Document object). That should let you do things like

    xfa.form.form1.resolveNodes("#subform[*]");

    in order to get a list of page-level subforms (assuming the current form’s root subform is named form1).

    I’m not promising that this works but I would hope that it does. In the end, however, it’s best to use application-level scripts only if absolutely necessary. Access to certain Acrobat Object Model objects in an XFA-PDF form may change in future releases and this could cause your scripts to break.

  11. Sérgio on August 31st, 2006

    Stefan,

    At first I tried to get the XFA object from an application/folder lever javascript function using “this.xfa”. The result was always “undefined”. Using a direct call to “xfa” was undefined too. However, using “event.target.xfa” works very well. All the properties/methods of the xfa object could be used this way.

    I think this is an important point to your great figure in this article: If I´m not wrong, using “this” in a folder level script return an Acrobat Document object, while event.target will return an xfa form object.

    So, maybe you could show that in your figure as it mainly shows the direction form xfa to acrobat and not the opposite with the exception of the get field function. I don´t know if I make my self clear about this… I´m only trying to figured out all these ways in my mind using your figure.

    In what relates to code breacking, I understand your point, however, I rather change the code in a javascript file than change it in about 400 documents… That is why I´m trying to put my code inside an external javascript file.

    Stefan, thank you for your help.

    Regards,

    Sérgio

  12. Stefan Cameron on September 5th, 2006

    Sergio,

    Thanks for your input.

    I see your point about code breakage and not wanting to update 400 forms to fix one little typo in a script. Hopefully you’ll like what a future version of Designer has to offer in order to address this sort of problem.

    With respect to the xfa object, I’d like to clarify that the reason why “event.target.xfa…” works is because “event.target” represents the active Acrobat Document Object and within that object lives an xfa object (as long as you’re dealing with an XFA-PDF form). From there, you can access the XFA Form Object Model by doing things like

    event.target.xfa.form.form1.resolveNode("#subform[0]").myField.rawValue = 'test';

    in order to assign the value “test” to a field named “myField” on the first page of a form named “form1″.

    As far as the “this” keyword in Acrobat application level scripts goes, while I’m no Acrobat scripting expert, I’m quite certain that “this” usually refers to the app object (Acrobat Application) instead of an Acrobat Document Object. You would have to get the list of opened documents and then test each one for the existence of the xfa object. For example, you could do something like this (please note that I haven’t tested this Acrobat script):

    var aOpenDocs = app.activeDocs;
    if (aOpenDocs.length > 0)
    {
      var oDoc = aOpenDocs[0];
      if (oDoc.xfa != null)
      {
        // access the xfa object...
      }
    }
  13. Sérgio on September 6th, 2006

    Stefan,

    What do you mean about this:

    “Hopefully you’ll like what the next version of Designer has to offer in order to address this sort of problem.”

    What version of Designer are we talking about? I believe it will be a new release right?

    Thank you!

  14. Stefan Cameron on September 9th, 2006

    Sergio,

    Curious, are we? ;)

    I’m talking about a new release of Designer. Unfortunately, that’s about all I can say at this point.

  15. Sérgio on October 24th, 2006

    Ok,

    Another question less curious, about the new table object of Designer 7.1.

    Is it possible to add new columns programmatically or at least, hide columns already in the table?

    Thank you!

  16. Stefan Cameron on October 28th, 2006

    Sergio,

    In response to your question on table columns, check-out my post on Scripting Table Columns.

    I hope it answers your questions.

  17. smvo on January 3rd, 2007

    Hello Stefan,

    Here I am again, now that I´m trying to use LiveCycle Forms.

    Well, after all the code created in LiveCycle Designer, and because I used some acrobat objects and application level code, I am now stuck in some issues:

    1 – I need to use something like a xml string reader. So I used XMLData object in Livecycle Designer. In LC Forms I only get this: Object302394736

    Does this menas that there is not a way to work with xml strings using xfa (to be compatible with Livecycle Forms)? This is really bad, because I will need many hidden fields to accomplish the sabe functionality…

    2 – I use a lot of application script because I don´t want to get big PDF files. However, I guess this will not work in LC Forms, right? Is there any sort of code container to LC Forms similar to the acrobat install script Directory where we put javascript files? So that when the script is not on the form, LC Forms will search somewhere else?

    Thank you.

  18. Stefan Cameron on January 8th, 2007

    smvo,

    I’m afraid it’s 0 for 2 on this one.

    Since the XMLData object is an AcroForm object, it isn’t available to the scripting model when the form is running on Form Server.

    As for your question about a central place to put global JavaScript scripts on the server, this isn’t possible either.

    I’m afraid you’re best bet here is to write a little XML parser in JavaScript (I know, that’s really not what you wanted to hear and it’s not what I wanted to be able to tell you either) and to place all scripts in the form itself.

  19. smvo on January 15th, 2007

    Stefan,

    I decided to use arrays.

    Tell me, is there a way to get the full path to an object? For instance, in an object event: this.some_propertie_to_get_the_full_path_of_it?

    Thank you

  20. smvo on January 17th, 2007

    ok, I had figured out: this.somExpression

    Thank you

  21. wnged on March 19th, 2008

    hi Guys,

    I have form which is built in Adobe LifeCycle version 8. of SP2. I am looking for a way to tell whether my form is open within an IE browser or normal Acrobat reader.

    I try to use the method of target.event.internal or this.external, however it returns undefined.

    Can you shed some lights on this question ?

  22. Stefan Cameron on March 20th, 2008

    wnged,

    That’s an interesting question! There are a couple of things you try: First, if Acrobat/Reader is loaded in-place within a browser, the

    event.target.hostContainer

    property will be defined. It provides a reference to the browser, if I’m not mistaken. If the form is loaded in Acrobat/Reader standalone, the property will not be defined. Note that this property isn’t supported on the Mac OS so if your form is loaded within the Mac OS, you wouldn’t be able to tell either way.

    If that doesn’t work-out, then you could try parsing the

    event.target.URL

    property which is the document’s URL. If the form is loaded locally, the URL will start with “file://” and this would indicate a pretty good change that it’s loaded in Acrobat/Reader standalone (but this isn’t 100% accurate since the user could’ve loaded your form within their browser from a local web server). Otherwise, the URL will likely be “http://” which means the form is likely loaded in Acrobat/Reader which is, in turn, loaded in a browser.

  23. wnged on March 25th, 2008

    Stefan,

    Thank for your suggestion. The target.hostContainer did not work, it returns undefined in either Reader Standalone or Browser running in window OS.
    The event.target.URL works as it returns the file or http. My problem is that I have used event.target.URL in my form. however
    the new version of Reader 8.1 or above displays a security warning when you use the target.URL. This annoys user to click OK each time openning the form.

    I try to avoid to execute the event.target.URL by trying detecting whether the form is opened in browser or stand-alone. if it opens in stand-alone, it can by-pass the code and
    avoid the warning message. sofar I cannot find otherway to detect this, apart using the event.target.URL.

    I am keeping looking..

  24. Fran on April 30th, 2008

    Hi, try with this, it worked to me ;)

    var oParent = event.target;
    if ( oParent.external )
    {
    // Viewing from a browser
    console.println(“Viewing from a browser”);
    }
    else
    {
    // Viewing in the Acrobat application.
    console.println(“Viewing in the Acrobat application.”);
    }

  25. Mike on August 19th, 2008

    In looking for some help, I found this post. Maybe you can answer this question: I am using Pro 8 and am having an issue with newly created forms. We use an application to import the form and map the fieldnames to our application for printing purposes, however by default, new forms are created with Designer in the new format. This new format does not work with our application, and I need to create new forms in the “old” acroforms method.

    I can open these new forms in Pro, but under Forms toolbar, can only edit the form in Designer. Old forms will allow me to edit in Acrobat. I can work around this problem by opening an old document, saving as a new doc and adding my new pages and deleting the old. I can then edit the form in Acrobat instead of Designer, but this is cumbersome, and I have to be able to train new users to do this. I would be much more efficient to be able to select which way the new forms are created, but I cant find an option that allows that. Any ideas?

    Thanks

  26. Cheska on January 25th, 2009

    Hi Stefan,

    I am desperate to get a solution to my problem with average calculation using checkboxes. I hope you can help me. I am a first time user of the designer but was successful on completing my form. The problem came up when a numeric field to calculate average using checkbox values was not giving me the correct number. My form has a section with 7 rows or questions. I use 4 checkboxes to select answer. Boxes are set to global so only one check for each row. All 4 boxes in a row have the same fieldname. To calculate the average: sum of the values of the checboxes (1-4) / count of the checkboxes which is 7. The problem came up when only 5 rows are checked. How do I make the denominator a variable so that it will only count the checkboxes that are checked???
    Please help. Thanks in advance.

    Cheska

  27. Stefan Cameron on January 26th, 2009

    Cheska,

    I’m not quite sure I understand the way in which you’ve setup your checkboxes. On one hand, it sounds like you want them to be mutually-exclusive (i.e. users can only check one out of the set like radio buttons) however you also mention being able to select multiple checkboxes…

    Mutual-exclusivity aside, let’s say you had 7 checkboxes, each with an “on” value of 1 to 7 and an “off” value of 0, and you wanted to calculate the average based on the number of checkboxes checked. The numeric field that displays the average would have a Calculate script like this (with the language set to JavaScript):

    var total = 0;
    var checkedCount = 0;
    
    if (checkbox1.rawValue > 0)
    {
        total += checkbox1.rawValue;
        checkedCount++;
    }
    
    if (checkbox2.rawValue > 0)
    {
        total += checkbox2.rawValue;
        checkedCount++;
    }
    
    [...]
    
    if (checkbox7.rawValue > 0)
    {
        total += checkbox7.rawValue;
        checkedCount++;
    }
    
    // Careful not to divide by zero if no checkboxes are checked!
    if (checkedCount > 0)
        this.rawValue = total / checkedCount;
    else
        this.rawValue = 0;

    This isn’t the simplest script you could write but I think it makes it easier to grasp the concept this way.

  28. justin poyser on May 23rd, 2009

    Hi Stefan,

    I’ve been looking around for a while for an example that would show me how to create a popup whereby I can control the font size and color. I’ve had a look at the adobe javascript dialog reference and the xfa.host.messagebox api, but haven’t had much luck. Do you have any idea on how I can achieve this.

    Regards

    Justin

  29. Stefan Cameron on May 25th, 2009

    justin poyser,

    Unfortunately, these dialogs are created by Acrobat/Reader and can’t be modified.

  30. DebbieF on June 12th, 2010

    Stefan,

    I’m using Adobe LiveCycle Designer ES 8.2. I’ve successfully connected to a database and can populate the form by making selections from 2 drop downs. This works great thanks to the great posts shared in the forums.

    What I need to do next is to dynamically save the form to a file location based on text in the form. I’ve read all the blogs on this subject and my code error in the JavaScript console reads:
    doc is not defined.

    I’ve created and recreated many versions of the trusted function (folder level Javascripts – saved in the C:\Program Files\Adobe\Acrobat 9.0\Acrobat\Javascripts.

    Please, how do I get the doc to be recognized by the Adobe LiveCycle form? I’ve restarted Acrobat, etc. I’ve made all of the gotcha settings like enabling menu item JavaScript execution.

    Here’s the folder level JS function:

    // application folder function

    mySaveAs = app.trustPropagatorFunction(function(oDoc, cPath, cFlName)

    {

    app.beginPriv();

    oDoc.saveAs(oDoc, cPath, cFlName);

    app.endPriv();

    })

    myTrustedSpecialTaskFunc = app.trustedFunction(function(oDoc, cPath, cFlName)

    {

    // Check name of the current form
    var aDocumentFileName = this.documentFileName;

    // If name of the current form is … save it to the following target
    if (aDocumentFileName == “BOEForm.pdf”)

    // Privileged and/or non-privileged code above

    app.beginPriv();

    mySaveAs(oDoc, cPath, cFlName);

    app.endPriv();

    // Privileged and/or non-privileged code below

    });

    Here’s the mouseup event code in the Adobe LiveCycle Form-

    topmostSubform.Form1.Page1.Button2::mouseUp – (JavaScript, client)
    aDocumentFileName = this.documentFileName;

    var doc = “BOEForm.pdf”

    event.target.myTrustedSpecialTaskFunc(event.target, “/c/BOEForm.pdf”, “mySavedDoc.pdf”); //this should execute the save as js file

    And the JS Console Error Reports:

    doc is not defined
    9:XFA:topmostSubform[0]:Form1[0]:Page1[0]:Button2[0]:mouseUp

    I appreciate your help. I’m hoping to solve this so I can go on with life….

    Thank you!

  31. Kurt Lukas, Europe, Germany on June 16th, 2010

    Hello, Dear Sir Stef!

    Great area, your works!
    I´m searching for examples of the openList-method,
    because FormCalc,

    xfa.host.openlist(Formular1.#subform[0].DropdownListe1)

    doesn´t work;

    at your hint you use “@object” and “@string”, I´m sorry,
    what is some explicit syntax?!

    it´s great for user when they enter with tab or mouse
    a DateTime-Field and nothing more move to the little black
    triangle to click…..!

    please, what to do?!

    the code is so cool and so much cool because shortend!

    ThankYou Very Much! Yours Kurt Lukas.

  32. Kurt Lukas, Europe, Germany on June 16th, 2010

    Back, please, backward my question!!

    it works in any event of another control, I have uesed it errorly
    in the enter-event of the control itself;
    what is th ecorrect event to fire this nice little utility?!

  33. Kurt Lukas, Europe, Germany on June 16th, 2010

    ok, it works in MouseEnter-Event, but not in Enter-Event….what´s wrong, please?!

  34. Stefan Cameron on June 23rd, 2010

    @DebbieF,

    Could this simply be that you’re missing a semi-colon on the following line in your MouseUp event?

    var doc = "BOEForm.pdf"

    I don’t see one in the code you provided… Otherwise, I don’t see what would be going wrong.

  35. Stefan Cameron on June 29th, 2010

    @Kurt Lukas, Europe, Germany,

    “@object” was meant to be replaced by a reference to the drop down list object and “@string” was meant to be replaced by the drop down list’s SOM expression.

    The object reference variation is only supported in later versions. Have you tried this?

    xfa.host.openList(DropdownListe1.somExpression)

    (also note the capital “L” in “openList”).