The Form Object Model
The Adobe XML Form Object Model is based on XFA (the Adobe XML Forms Architecture). The Form Object Model organizes all of the objects and properties of your form into a tree structure. The XFA object is the top-level object, and there are a series of child Document Object Models (DOMs). This section provides information and scripting examples for the different DOMs. You'll find that scripting is easier in Designer once you have a working knowledge of the object model.
The Adobe XML Form Object Model is a topic that deserves its own book. In fact, Adobe has provided two very long technical reference guides to the object model:
- "Adobe XML Form Object Model Reference for LiveCycle Designer 8.0"
- "Adobe XML Form Object Model Reference for LiveCycle Designer 7.1"
In the "Navigating the reference documents" section, I'll show you how to retrieve valuable scripting information from these documents.
Understanding the Object Model
The XML Form Object Model is made up of a series of DOMs. Each DOM organizes various objects and properties in computer memory as a tree structure. Each DOM is a child of the root XFA DOM. By navigating these structures with your scripts, you can access the exact object and property you need. But before we look at the specific objects and properties, let's look at the big picture of how the DOMs work together. Figure 4.19 shows the organization of the DOMs included in the XML Form Object model.
Figure 4.19 The DOMs of the XML Form Object Model.
The XFA DOM
The XFA DOM is the wrapper for all the other DOMs. You have already been using xfa as the root element in all of your fully qualified scripting expressions. For instance, you have already written the following scripts:
- xfa.event.newText: This script calls the newText property, which is part of the event object in the XFA DOM.
xfa.resolveNode(): This script calls the resolveNode method of the XFA DOM.
This xfa root element will also be the prefix when you make a reference to one of its child DOMs.
- xfa.layout.pageCount(): This script calls the pageCount property of the Layout DOM.
The Template DOM
The Template DOM contains information about the form design. You will rarely, if ever, script against this DOM. The Form DOM has all of the same objects as the Template DOM as well as a few others. The Form DOM also has access to the data, but the Template DOM does not.
The Data DOM
The Data DOM contains the data structure and content. You can use this DOM to access any data element. However, you typically will only use this DOM to access hidden data. The Template and the Data DOM merge to create the Form DOM, and many of the data elements are bound to elements in the form DOM. Once these data elements are bound to form elements, you can access them by referencing the objects in the Form DOM.
The Form DOM
The Form DOM contains the Template DOM and the Data DOM. You will use this DOM for most of your scripting.
The Layout DOM
The Layout DOM contains page-specific information. You will use this DOM to write scripts to access specific page numbers or to retrieve a total page count or other page-related requirements, just as you did in a previous example:
this.rawValue = xfa.layout.pageCount()
Scripting the Form Object Model
All DOMs are not created equal when it comes to scripting. As you can see in Figure 4.20, certain DOMs provide more value for your form scripting. Open the file formObjectModel.pdf from the Samples folder for the exercises in this section.
Figure 4.20 Scripting the Form Object Model.
The Form DOM—the scripting default
The Form DOM is the most useful DOM because you can access both presentation and data information. The Form DOM is also the default DOM for all Designer scripting. You do not need to explicitly include the word form in your SOM expression, but it will work if you do.
Your sample form has two buttons—FormDOM_Explicit and FormDOM_Implicit—that accomplish the same task. The first button, FormDOM_Explicit sets the rawValue property of username to "John Warnock" by referencing the Form DOM explicitly:
xfa.form.order.page1.username.rawValue = "John Warnock";
The second button refers to the Form DOM implicitly:
username.rawValue = "John Warnock";
There are actually two reasons that the abbreviated statement works. I discussed the first reason in the previous section on referencing objects. The abbreviated reference works because the button and text field are both part of the same container object. The second reason that this abbreviated statement works is because it references an object and property in the Form DOM, and the Form DOM is the default for scripting.
The formObjectModel.pdf has a more advanced example of accessing the Form DOM objects with scripting. Select Preview PDF and enter 3 in the numberOfPants text field. When you press the Enter key or when you tab out of the field, the form creates three line items containing a length and width text field for each pair of pants (Figure 4.21).
Figure 4.21 A new line item is added based on the number of pants that the form filler requests.
Go back to Design View and select the numberOfPants text field. You will see the following script in the exit event:
var numField = this.rawValue; var count = xfa.form.order.page1.flowedSubform.positionedSubform.all.length var t; var r=0; if(count > 1){ for(t = 0; t < count-1; t++){ xfa.form.order.page1.flowedSubform.positionedSubform.instanceManager.removeInstance(1); } } for(t = 0; t<=numField -2; t++){ xfa.form.order.page1.flowedSubform.positionedSubform.instanceManager.addInstance(1); }
This script explicitly calls the form object to create a new instance of the pantDetails subform. A new instance is added by calling the addInstance() method of the subform's instance manager.
Accessing data values with the Data DOM
You will typically use the Form DOM to access data values in your scripting. The Form DOM contains the data elements that are bound to your form elements. However, if you need to access hidden data values that are not bound to a form element, you will use the Data DOM.
Open the dataDOM.pdf file in Designer to see an example of scripting the Data DOM. In this example, a form filler can cycle through a series of shirt colors and the form will immediately update with new values from the data file (Figure 4.22).
Figure 4.22 Cycling through shirt colors in the sample dataDOM.pdf file.
This form uses the shirtColor.xml file from the Samples folder, which contains the RGB (Red, Green, Blue) equivalents of six colors. If you receive a warning message about this file when you launch the PDF form in Designer, you may need to reestablish the link with this file. Simply select Form > Form Properties > Defaults and reestablish the link in the Data File field:
<ShirtColor> <entry> <Color>0,0,255</Color> </entry> <entry> <Color>255,0,0</Color> </entry> <entry> <Color>0,0,0</Color> </entry> <entry> <Color>255,128,0</Color> </entry> <entry> <Color>0,255,0</Color> </entry> <entry> <Color>255,255,0</Color> </entry> </ShirtColor>
This example uses various methods of the dataWindow object. The XFA dataWindow object represents all of the data records that are currently loaded into memory. You can see the following dataWindow methods in the click events of their respective buttons
-
First button: The click event of the First button contains the following script that takes you to the first record, which is blue (R = 0, Green =0, Blue=255):
xfa.dataWindow.gotoRecord(0);
-
Previous button: The click event of the Previous button contains the following script, which performs two actions. The first action verifies that the current record is not the first record in the dataWindow. If it is, the script provides a message box that informs users that they are on the first record. If it is not, the script calls the moveCurrentRecord method of the dataWindow object:
if (xfa.dataWindow.recordsBefore > 0) { xfa.dataWindow.moveCurrentRecord(-1); } else { app.alert("This is the first record in the data file."); }
-
Next button: The click event of the Next button contains a script that is similar to the Previous button but in this case it verifies that users are not on the last record of the dataWindow:
if (xfa.dataWindow.recordsAfter > 0) { xfa.dataWindow.moveCurrentRecord(1); } else { app.alert("This is the last record in the data file."); }
-
Last button: The click event of the Last button contains the following script, which takes users to the last record. The last record is calculated by adding the index value of the current record to the number of records after the current record:
xfa.dataWindow.gotoRecord(xfa.dataWindow.currentRecordNumber + xfa.dataWindow.recordsAfter);
For this example to function, you need to manually add a line of code to the XML source for the form. To view this line of code, switch to the XML Source tab and do a search for the following line of code using Designer's Find feature in the Edit menu:
<record>entry</record>
Event and host objects in the XFA DOM
The XFA DOM has two important objects that you have already used in previous scripts:
- The event object: By scripting the event object, you can retrieve information about form changes that occur before, during, and after actions take place. These actions include events that are fired as the form is rendered as well as interactive events that are fired by the form filler's actions. You saw an example of this object in the "Getting and setting properties" section. There is another example in the "Sending Email Through Scripts" section in Chapter 6.
- The host object: The host object refers to the container for your form, which will most likely be Adobe Acrobat or Adobe Reader, but it could be a Web browser. This object, which includes the message box, is only available at runtime.
The following script uses the host object to determine the container for your form:
TextField1.rawValue = xfa.host.name + " " + xfa.host.version;
On my computer, this script produces the string "Acrobat 8" because that is my container name and version number. Yours may be different. You can see more examples of how the host object is used in scripting in these sections of Chapter 6: "Message Box Scripts," "Working with Page Numbers," "Disabling All Form Fields."
Accessing page information with the Layout DOM
The Layout model is the final in-memory representation of the form. As mentioned previously, you will script against the Layout DOM to access page-related information. The Form DOM does not contain this page-related information. The following script shows how to access the Layout DOM to retrieve the current page number:
TextField1.rawValue = xfa.layout.page(this);
The previous script that counted the number of text fields in a form also referenced the Layout DOM:
var oFields = xfa.layout.pageContent(nPageCount, "field");
No scripting with the Template DOM
You typically do not script against the Template DOM for two reasons. First, the Form DOM has all of the same objects as well as some additional objects. Also, the Form DOM has access to the form's data so it is a much better DOM to script against. Second, the Template DOM is simply more difficult to work with than the Form DOM. According to Adobe, you will need, "a thorough understanding of the merge and layout processes. In some cases, you have to request a remerge and relayout to see the results of any changes." I have never used this DOM for any real-world programming work.
Navigating the reference documents
The current "XML Form Object Model Reference" from Adobe weighs in at a trim 412 pages (Figure 4.23). The previous version for Designer 7.1 was a full 695 pages, which made it a rather heavy PDF to carry around. Both documents have all the detailed information that you need about the objects, properties, and methods of the XML Form Object Model. However, these reference documents are long and very technical. I recommend navigating these documents using their internal PDF links.
Figure 4.23 "XML Form Object Model Reference" in Adobe Acrobat.
Follow these steps to navigate the reference documents to get information about the messageBox object:
- Open the reference document in Acrobat or Reader. This example uses the version 8 document.
- Select the "XML Form Object Model DOMs" section under the "Understanding the XML Form Object Model" section.
- Select the Host Model and under the Host Model header, select the link titled, "'hostPseudoModel' on page 78."
- Page 78 lists all the properties and methods of the host object. Select the messageBox link to see detailed information on the messageBox. The message box has the following syntax:
messageBox(STRING param1, STRING param2, INTEGER param3, INTEGER param4)
The parameters are also listed and described in Table 4.2.Table 4.2. Parameters for the MessageBox
Parameter
Description
param1
A valid string representing the message to display
param2 (optional)
A valid string representing the title to appear in the title bar
param3 (optional)
An integer representing the icon to display in the dialog box 0 (Error) default, 1 (Warning), 2 (Question), 3 (Status)
param4 (optional)
An integer representing the buttons to display 0 (OK) default, 1 (OK, Cancel), 2 (Yes, No), 3 (Yes, No, Cancel)
- FormCalc and JavaScript scripting examples are also located below the parameters table. These are usually useful, but in this case the syntax for the JavaScript example is wrong. The syntax description is correct, but the example is wrong. The following example creates the messageBox illustrated in Figure 4.24.
Figure 4.24 This messageBox is created by setting all of the optional parameters of the messageBox object.
xfa.host.messageBox("This is the message", "This is the title", 2,3);
As you can see, these documents are chock full of valuable information. Along with a good book on JavaScript and this chapter, you will be able to use these documents to write any scripts that your forms require.