How to Create Scripts for Online Forms with Adobe LiveCycle Designer

Date: Oct 5, 2007 By J. P. Terry. Sample Chapter is provided courtesy of Adobe Press.
Digital forms expert J.P. Terry shows you how to improve the functionality and usability of your online forms through scripting.
  • A good programmer is someone who always looks both ways before crossing a one-way street.
  • —Doug Linder

Scripting is optional in Designer forms. You can achieve a great deal of functionality and customization without scripting. And you can set most of the important property values of your form objects at design time by using Designer's palettes. You have already learned a lot about these property settings in previous chapters, and you will learn more in Chapter 5, "Form Data." But this chapter focuses on setting and getting these property values at runtime through scripting.

Scripting gives you full control over your form's functionality at runtime. Through scripting you have the power to manipulate your form's interactive controls to provide your users with a richer and more intuitive experience. Designer scripting is similar to HTML scripting in the following ways:

  • Use of JavaScript: You use JavaScript to write custom scripts that add functionality to your forms like you use JavaScript to add custom functionality to a Web page. Designer also includes another language called FormCalc, which is covered in this chapter.
  • Use of an object model: Like Web programming, Designer also has an object model that you can use for your scripting. You can call methods and properties of the object model to provide powerful functionality to your forms.
  • Range of scripts: Because JavaScript is a rich, object-oriented scripting language, you can write an incredible range of scripts, from very basic one-line scripts to complex and detailed, object-oriented scripts that can span hundreds and even thousands of lines.

If you are familiar with scripting on the Web or another platform, you will find the scripting concepts in Designer to be very familiar. However, the execution details of scripting in Designer are unique and are reviewed in this chapter.

The Benefits of Scripting

In many cases, scripting improves the functionality and usability of your forms. You can see this in action by opening the Purchase Order form from the Samples folder (it can also be found in Designer's Help System). A number of useful scripts are included in this form. One of these handy scripts is found in the Add Item button's click event (Figure 4.1). This script creates a new line item in the purchase order each time the button is clicked. In the previous chapter, you saw how this was made possible by the form's subform structure. However, it is the script that calls the subform's instance manager with the directive to create a new instance. This script runs on the button's click event.

Figure 4.1

Figure 4.1 Two scripts from the Purchase Order form show the benefits of adding scripting to your forms.

Another practical script is found in the Grand Total text field (numGrandTotal). This script automatically calculates the grand total for the purchase order every time a financial event on the purchase order occurs. When a new item is entered or when a new tax is applied, the grand total is automatically recalculated. This is a very useful script for form fillers because they can see how all of their changes and additions to the purchase order affect the bottom line. Unlike the previous script, which ran on the click event, this script runs on the text field's calculate event. You'll learn how these different events affect your form's performance in the "Events" section later in this chapter.

Although you don't absolutely need scripting in your forms, a small investment in scripting will yield all of the following benefits to you and your form fillers:

  • Automatic calculations at runtime. As described in the purchase order example, the addition of automatic calculations makes your forms much more useful to your form fillers.
  • Ability to control the appearance of form objects at runtime. In the previous chapter, you set the visual properties of your form objects at design time. With scripting, you can make changes to the visual properties of your form at runtime to provide assistance to your form fillers. For instance, before your users submit a form, you can use a validation script to check to make sure that all of the required fields have been filled in with data. If there are required fields without data, you can call a script to highlight them in yellow. This way, the form fillers' attention is visually drawn to the required task.
  • Enforcement of business rules. You can use form scripting to enforce the business rules of your company or industry. For instance, the purchase order example could have a script that takes an action whenever the grand total goes above a certain threshold. You could create a script that limits users from going above a certain amount, or you could allow them to go above the amount and automatically route the purchase order for a senior manager's approval.
  • Data validation and formatting. In addition to using patterns and properties to enforce data validation, you can use custom scripting. This is very valuable because you will be able to correct many data entry mistakes before they get to your back-end system.

FormCalc and JavaScript

LiveCycle Designer supports scripting in two languages: FormCalc and JavaScript. A form can use both languages at the same time, but you cannot mix the two languages in one object event. FormCalc is an easy-to-use calculation language that Adobe developed for use in XFA forms. It is very similar to calculation language that you use in a spreadsheet program like Microsoft Excel. JavaScript, on the other hand, is a powerful, object-oriented scripting language that many programmers are already familiar with. This book focuses on JavaScript but also includes a few FormCalc examples.

FormCalc

FormCalc is not as powerful or as ubiquitous as JavaScript. However, it is ideal for nonprogrammers who need to add calculations to their forms. If you come from a Microsoft Excel background and you don't have any JavaScript experience, you should consider using FormCalc. FormCalc has many built-in functions that cover a range of areas including finance, logic, dates/times, and mathematics. FormCalc is supported in Designer, Acrobat, Reader, and in the LiveCycle Servers. However, it will not work with the HTML forms created by LiveCycle Forms.

Like Excel, most FormCalc scripts are only one line long. The following code sets the rawValue property of TextField1 to the sum of (1,2,3,4), which is 10:

form1::ready:form - (FormCalc, client) ----------------
TextField1.rawValue = Sum(1,2,3,4)

The first line of code is a script header that gives you important information about your script. The first part indicates that the script is running in the form:ready event; the second part shows you that the language is FormCalc and the script is running on the client. These headers are also used when you are working with JavaScript.

Date and time functions

FormCalc has many functions that are ideal for the common tasks that interactive forms require. For instance, the following script sets a Date/Time Field to the current date:

form1::ready:form - (FormCalc, client) ----------------
// Today's Date in long-style date format.
DateTimeField1.rawValue = num2date(date(), DateFmt(3))

The second line is a script comment and will be ignored by the script interpreter. You can add a comment line to your FormCalc or JavaScript code by beginning the line with two slashes "//". You can also add a comment line to a FormCalc script by preceding it with the semicolon ";" symbol. Additionally, you can add a comment block to your JavaScript code by beginning the block with the "/*" characters and ending it with the "*/" characters.

Financial functions

If you are working on financial forms, FormCalc has many built-in financial functions that you can add to your form. For instance, it is easy to calculate the APR (annual percentage rate) of a loan with FormCalc. In the following example, the principal amount of the loan is $35,000, the monthly payment amount is $269.50, and the total amount of months is 360. This script returns an annual percentage rate of 0.08515404566 to TextField1:

form1::ready:form - (FormCalc, client) ----------------
TextField1.rawValue = Apr(35000, 269.50, 360)

Adding FormCalc to your forms

To see FormCalc in action, open a blank form and add a Text Field and a Button object. Follow these steps to add a FormCalc script to each of your objects.

  1. Select the Text Field object and select the form:ready event in your Script Editor (Figure 4.2).
    Figure 4.2

    Figure 4.2 Inserting a built-in FormCalc function into your script.

  2. Click on the script editing field to create a blinking "I" beam. While in this mode, select the Functions button and select the Concat(s1[,s2...]) function (Figure 4.2). Double-clicking this item inserts the Concat function into your script.
  3. Complete your script by adding a reference to your Text Field object's rawValue property:
    form1::ready:form - (FormCalc, client) ----------------
    TextField1.rawValue = Concat("Live", "Cycle")
    
    The Concat function in FormCalc returns the concatenation of two or more strings. In this example, the Concat function joins the string "Live" with the string "Cycle" to form the word "LiveCycle." This new value is assigned to the rawValue property of the text field. You can use string functions like Concat in your forms to join a user's first name with his last name to create a full name value.
  4. Select the Button object and add the following code to the click event:
    form1.#subform[0].Button1::click: - (FormCalc, client) --------
    $host.messageBox("Hello, World!")
    
    When you click this button, a pop-up message box with the phrase "Hello, World!" appears. The "$host" item is a FormCalc shortcut that represents the host object. To reference the host object in JavaScript, you use the following syntax:
    form1.#subform[0].Button1::click: - (JavaScript, client) --------
    xfa.host.messageBox("Hello, World!")
    

This chapter will cover more about the host object and the other object models in XFA forms. If you are interested in exploring FormCalc further, Adobe has included excellent reference materials in the Help section including the "FormCalc User Reference," which you can find under the Scripting section of the Help System.

JavaScript

Although FormCalc is the default scripting language in Designer, JavaScript is more ideal for creating sophisticated interactive and dynamic forms. The following are some of the advantages of using JavaScript.

  • JavaScript is ubiquitous. It is very likely that you will be able to leverage your organization's existing JavaScript knowledge because JavaScript is a scripting standard that many programmers and designers already know.
  • JavaScript is object-oriented. You can create JavaScript objects and custom functions, and use them throughout your form. This feature of JavaScript is not available in FormCalc, and it enables you to eliminate work by allowing you to reuse your code.
  • 50,000 JavaScript fans can't be wrong. Because JavaScript has been a scripting standard for a long time, you will be able to find sample scripts for almost everything you need to do. You can find these sample scripts on the Web, in JavaScript books, and in this book.
  • JavaScript works for PDF and HTML forms. If you are creating XDP files that you want LiveCycle Forms to render as both PDF and HTML forms, you must use JavaScript.

The Script Editor

The Script Editor is the tool you use to create and edit scripts. You can view the Script Editor in either single or multiline view. Unless you are creating one-line scripts in FormCalc, you should use the multiline view. The multiline view provides a number of features that the single-line view does not. To switch between the multiline view and the single-line view, click and drag the Script Editor palette bar until the palette is the required size (Figure 4.3).

Figure 4.3

Figure 4.3 Click and drag the Script Editor palette bar to switch from single to multiline view. If you single click on the palette bar, the Script Editor toggles open and closed.

If you cannot see the Script Editor on your screen, select Window > Script Editor.

The Script Editor in Single-line View

Figure 4.4 shows the Script Editor in single-line view. Notice how small the script editing window is. Even my very short script was truncated. This example shows the Print button from the Contact Information form.

Figure 4.4

Figure 4.4 The Script Editor in single-line view.

The Script Editor shows the following information in both single and multiline view:

  • Event: In this case the event is the button's click event. The asterisk indicates that there is script in this event. If you select the event drop-down menu, you will see all of the events for this object. Grayed out events are not available for this form object.
  • Script editing window: This is where you write and edit your scripts.
  • Enter/Cancel a script source change: These buttons commit or cancel your script source changes to your XML source. If you do not commit your script changes with this button, they may not execute properly when you select Preview PDF. These buttons were removed in Designer ES.
  • Script Language specification: In this case, the Language is set to JavaScript. Even if you put proper FormCalc script into this box, it will not work.

The Script Editor in Multiline View

You should use multiline view if you are working with JavaScript. In addition to showing your complete script, the multiline view also provides more features than the single-line view (Figure 4.5).

Figure 4.5

Figure 4.5 The Script Editor in multiline mode provides additional options.

  • Functions button: While you are working in the script editing field, you can click this button to view a list of FormCalc or JavaScript functions depending on your Language setting.
  • Show events for child objects: This feature is a welcomed improvement in LiveCycle Designer 8. You can now see all of the scripts for a subform, a page, or for your entire form at once. Prior to the addition of this feature, it was very difficult to find all of the scripts that were hidden in different parts of a complex form. This option shows all of the scripts for the currently selected object and all of its child objects. If you select the top form object in the hierarchy, this option displays all of the scripts associated with a specific event. Alternatively, you can change from a specific event to view all events by selecting Events with Scripts to see every script in your form.
  • Run At specification: This option specifies where your script will run. The Run At specification in Figure 4.5 is Client, which means the script will be processed by Acrobat, Adobe Reader, or a Web browser. If the specification is set to Server, the script is processed by LiveCycle Forms. If LiveCycle Forms is not part of your system, you should always use the Run At Client option. The third Run At option is Client and Server. Use this setting when you are not sure if your form will be rendered on a client or a server, or for forms that may be rendered on both the client and the server at different times. For instance, if your form will be used as a self-contained PDF file and as an XDP file that will be processed by LiveCycle Forms into an HTML form, use the Client and Server setting for your scripts.

    You can choose this option when you want the server to recalculate and/or revalidate submissions that were first calculated in the client application. You can also use this option when you are creating HTML forms with the LiveCycle Forms product. If you have a script that cannot function in the HTML client environment, it will be passed back to the server for processing if the Run At specification is set to Client and Server.

The Check Script Syntax tool in Designer ES

Designer ES includes the Check Script Syntax tool (Figure 4.6) as part of the Script Editor. This tool provides some basic syntax checking for FormCalc and JavaScript, and is discussed in the "Debugging Scripts" section at the end of this chapter.

Figure 4.6

Figure 4.6 The Check Script Syntax tool is included in the Script Editor of Designer ES.

Basic Scripting

Scripting in LiveCycle Designer is simple enough that you can begin today but robust enough that you won't be bored even after years of programming. If you don't know any JavaScript, don't worry, the examples in this book will help get you started. If you are a JavaScript god, that's great, LiveCycle Designer gives you a chance to show off your divine powers.

Let's begin by looking at two examples that illustrate how simple and how complicated JavaScript can be in your LiveCycle Designer forms. After looking at these two examples, I'll discuss the basics of creating variables and referencing Designer objects.

Your First Scripts

Many prebuilt scripts are available in the Designer program and in the Help System. This section covers the predefined scripts that are built into the Designer program.

Predefined scripts on the Insert menu

Some basic scripts are built into the objects on the Insert menu. Follow these steps to learn more about the basic scripts contained on the Insert menu.

  1. Add a Text object to a blank form. Type the following phrase into your Text object: My form currently has X page(s).
  2. Highlight the "X" in your Text object and select Number of Pages from the Insert menu. Designer changes your X to a Numeric Field object represented by the "##" characters (Figure 4.7).
    Figure 4.7

    Figure 4.7 Inserting a Number of Pages script into a Text object.

  3. Select this Numeric Field object, and you will see that Designer has added the following script to its Layout Ready event:
    this.rawValue = xfa.layout.pageCount();
    
    This script calls the pageCount property of the Layout DOM and assigns the value to the rawValue property of the current object, which is the Numeric Field. The keyword "this" always refers to the current object in Designer JavaScript.
  4. Select Preview PDF. You should see the following line of text: My form currently has 1 page(s).
  5. Go back to Design View and select Insert > New Page.
  6. This time when you select Preview PDF, you should see that your text has changed from 1 page(s) to 2 page(s). You can follow this method to review the other scripts that are predefined in the Insert menu objects.

Predefined scripts in Custom Objects

Some scripts are also built into the objects in the Custom Objects section of the Library palette. The Email object contains a more advanced script than those previously discussed. Drag and drop the Email Address object onto your form. Select the validate event for this object, and you'll see the script in the script editing field of your Script Editor (Figure 4.8).

Figure 4.8

Figure 4.8 The validation script for the Email Address custom object.

This multiline script begins to hint at some of the power of Designer scripting. The goal of this script is to validate the email address that a user enters. Here's how it works:

  1. A form filler enters an email address into the text field. The validate event of the text field fires when the user exits the field by tabbing, pressing the Enter key, or selecting another object.
  2. The script runs when the validate event is fired. The script first creates a new regular expression object and assigns it to the variable r.
  3. The script then assigns a regular expression to r by using the compile method of r.
  4. The form filler's entry is now tested against the regular expression by calling the test method of the variable r. The results of this text are stored in a new variable called result.
  5. If the entry matches the regular expression, the result variable is set to True and the validation passes. However, if the entry does not match the regular expression, the validation fails and the script returns the value of False. If the validation fails, the user will see the Validation Script Message appear in a pop-up message box (Figure 4.9).
    Figure 4.9

    Figure 4.9 The Validation Script Message appears to the user in a warning message (left) and to the form designer on the Value tab of the Object palette (right).

Properties

So far, you have been setting the property values for your form objects through the interface tools at design time. You can also set and get these properties through script at runtime. Open the form that you created from the XML Schema in Chapter 2, "Form Creation." You will use this form to work through some examples of setting and getting object properties through scripting.

Setting properties

Before you begin, move all of the objects so they are aligned in a vertical column. Add two new Text Field objects called currentShirtSize and previousShirtSize directly below the shirt size Drop-down List object. Reorder the objects in your Hierarchy menu so it matches the order on your form. Your form and Hierarchy palette should look like Figure 4.10.

Figure 4.10

Figure 4.10 The new hierarchy and layout of your form.

  1. Drag and drop a Button object onto your form and name it setProperties. Set the caption of the button to Set Properties in the Object palette.
  2. The Username object has a default value of "your name here." You can change this value with script by setting the rawValue property of the Username object. Select the setProperties Button object and select the click event from the Script Editor's Show menu. Type in the following line of JavaScript.
    username.rawValue = "John Warnock";
    
    As you typed the period after the object name, you might have noticed Designer's statement completion functionality. When you enter a period directly following an object or property name, Designer displays a list of available properties and methods. The statement completion list only appears when you access objects, properties, and methods of the XML Form Object model. It lists context-sensitive properties and methods of standard JavaScript.
  3. Type in another script directly below your previous script. Be sure to end each line with a semicolon:
    username.font.typeface = "Courier New";
    
  4. Select Preview PDF, and you will see that the Username object now displays a value of "John Warnock" in the Courier New typeface.
  5. Add the following lines of script to set other property values:
    pantsWaist.border.edge.color.value = "255,0,0";
    pantsLength.presence = "hidden"
    numberOfPants.presence = "invisible"
    
  6. To set the date, you need to first create a new JavaScript Date object and assign it to a variable named d. In the second line of script, you will call the toString() method of your Date object and assign the value to the rawValue property of your orderDate object:
    var d = new Date();
    orderDate.rawValue = d.toString();
    
  7. The final two scripts set the caption and background properties of a text field. Add these two lines to your setProperties click event to highlight the Username field in yellow and set its caption to "Full Name":
    username.caption.value.text.value = "Full Name";
    username.ui.textEdit.border.fill.color.value = "255,255,0";
    

Getting properties

You can also use script to get object properties at runtime. You saw an example of this earlier in the chapter in your first script example from the Insert menu:

this.rawValue = xfa.layout.pageCount();

Two other scripts that are already in your form retrieve form object properties. These scripts are in the validate event of the pantsLength and pantsWaist text fields. You saw how these scripts worked when you first previewed this form in Chapter 2. Since they are similar, let's look at the script in the pantsLength object. If a user enters a number lower than 28 or higher than 40 into the pantsLength text field, the validation will fail and a warning message box will appear (Figure 4.11).

Figure 4.11

Figure 4.11 A warning message box.

Select the pantsLength text field and look at the script in the validate event:

this.isNull || (this.rawValue >= 28 && this.rawValue <= 40);

This script retrieves two properties of the text field: the isNull property and the rawValue property. The JavaScript keyword "this" always refers to the current object, which in this case is the pantsLength text field. The double pipe "||" between the two statements is the JavaScript logical OR operator. The script will validate to True if either statement is true. In this case, if the text field is null or the text field contains an entry between 28 and 40, the script will return True. Because you are using the OR operator, you only need one statement to evaluate to true in order for the field to pass the validation.

The warning message is system generated. You can add a custom message by entering a sentence into the Validation Script Message field on the Value tab of the Object palette. Enter the following Validation Script Message to make your form a little more user friendly: Sorry, we don't have that size. Please enter a length between 28 and 40. You can improve this interaction even more by providing notification before correction, as discussed in Chapter 2.

Getting and setting properties

The following example pulls everything together by getting and setting property values. Open the file formFromASchema_withVariables from your Samples folder.

  1. Select the shirtSize Drop-down List object and locate the change event under the Show menu.
  2. You will see the following script that gets and sets property values:
    currentShirtSize.rawValue = xfa.event.newText;
    previousShirtSize.rawValue = xfa.event.prevText;
    
    These scripts get a property value from the xfa.event object and use it to set the rawValue property of a text field. More detail about the xfa.event object is provided in the upcoming section "The Form Object Model."
  3. Select Preview PDF and make a few different choices in the shirtSize Drop-down List. You will see that the currentShirtSize text field is populated with the current choice, and the previousShirtSize text field is populated with the previous choice (Figure 4.12).
    Figure 4.12

    Figure 4.12 The script runs on the change event of the Drop-down List.

Variables

A variable is a symbolic representation that refers to a place in computer memory that holds a value. Variables are advantageous because they enable you to define a value in one location but refer to it from many. When you need to change the value, you do not need to go back to each variable reference. You only need to go back to the one location where the variable is defined to make your change. All other locations that refer to the variable will be updated. This section focuses on the following two primary variable types:

  • Form variables: Are declared and assigned in the Variables tab of the Form Properties dialog box.
  • Script variables: Are declared and assigned in your scripts.

Form variables

A form variable typically acts as a placeholder for a value that you might have to change in the future. For instance, you can create form variables for state tax rates (Table 4.1). When you need to calculate the sales tax, you reference the form variable in your script. When you need to change the tax rate, all you have to do is open the form variable in the Form Properties dialog box and make the change (Figure 4.13). Because you referenced the form variable, not a specific numeric value, you do not need to update the tax rate in multiple locations on your form. Form variables are global in nature, which means that you can access them from any part of your form. The values of your form variables will reset each time the form is opened.

Table 4.1. State Sales Tax

State

Current Value

Future Value

Connecticut

5 %

Probably higher

New Jersey

6 %

Probably higher

New York

7 %

Probably higher

Figure 4.13

Figure 4.13 Entering a form variable into the Form Properties dialog box. Your form variable values will be reset to their original values each time the form is opened.

Follow these steps to create a form variable:

  1. Select File > Form Properties.
  2. Select the Variables tab and click the green button with the plus sign.
  3. Enter varUsername as your variable name and then enter Charles Geschke as your variable value (Figure 4.13).
  4. You can now make a reference to this variable from anywhere on your form. Go back to your setProperties button and change the Username script so it refers to this variable:

    username.rawValue = varUsername.value;
    

    This example uses two different property values to refer to similar information. When you need to access the value of an XFA field or form object, use the .rawValue property. When you need to access the value of a JavaScript variable or object, use the .value property.

    If you are working in FormCalc, you can retrieve the value of the variable without explicitly referencing a value property:

    order.#subform[0].fromVariable::click: - (FormCalc, client) -----
    username.rawValue = varUsername
    
  5. Select Preview PDF and click the Set Properties button. You will see that the new value is "Charles Geschke."

Even though you were able to create a form variable without scripting, you must use scripting to work with your variables in the following ways:

  • To access the value of your variable
  • To change the value of your variable at runtime
  • To apply the value of your variable to a form object

Open the file formFromASchema_withVariables.pdf from your Samples folder. In this example, you will see how the state tax rates are entered as form variables. You will also see two other form variables that track the shirts and pants inventory.

  1. Select File > Form Properties and click the Variables tab to review the form variables (Figure 4.14).
    Figure 4.14

    Figure 4.14 The form variables from formFromASchema_withVariables.pdf.

  2. Select Preview PDF and click the State Drop-down List object. When you select a state, the state tax amount will populate the tax text field.
  3. Go back to Design View and select the State Drop-down List object. You will see the following script in the change event of the Show menu:
    if(xfa.event.newText == "Connecticut"){
     tax.rawValue = ct.value;
    }else if(xfa.event.newText == "New Jersey"){
     tax.rawValue = nj.value;
    }else if(xfa.event.newText == "New York"){
     tax.rawValue = ny.value;
    }
    
    Notice that each state instance in the script refers to the state variable, not a numeric value.
  4. Select File > Form Properties and click the Variables tab to change the tax rates in your form variables. I bet you always wanted the power to change tax rates!
  5. Select Preview PDF and click the State Drop-down List object. This time, the tax text field will be populated with the new values that you entered in the form variable.
  6. While you are in Preview PDF mode, enter 251 in the Number of Pants text field. You will see a message box informing you that your number is too large (Figure 4.15).
    Figure 4.15

    Figure 4.15 This custom message was set in the Value tab of the Object palette.

  7. Go back to Design View and select the numberOfPants text field. You will see the following script in the validate event of the Show menu:
    this.rawValue <= totalPants.value;
    

Notice again that your script refers to the form variable. If your inventory changes, you can easily change this variable and your form's functionality will automatically be updated.

Script variables

Unlike form variables, script variables are local in nature. A local variable is used only within the scope of the script in which it is declared. If a variable is declared in one script and then referenced in another script, an error will occur. Local variables are used when their stored values are not needed after the script is completed. Once the script is finished, the memory that was assigned to the local variable is released and is able to be used for other purposes, helping to improve form performance.

You declare a script variable before it is first used in your script. The following example uses the JavaScript var operator to declare a variable named testVar. Once declared, the value of the variable is set to the rawValue of the text field:

var testVar;
testVar = textField1.rawValue;

Thereafter, you can reference or change the variable at any point throughout the script.

Referencing Objects

You have been writing code to reference objects in all of your previous scripting examples. This section covers the various ways that you can reference an object in Designer scripting. Although there are some minor differences, FormCalc and JavaScript both follow the same syntax when referencing objects. The syntax for referencing objects is described in this section and object structure is covered in the "Form Object Model" section.

Open the Purchase Order form in Designer and add a new button to the commentsHeader subform directly below Button3. Name your new button, "exampleButton" (Figure 4.16). It is very important for the examples in this section that this button be put in the commentsHeader subform.

Figure 4.16

Figure 4.16 Add an Example Button to your Purchase Order form.

Fully qualified reference

A fully qualified reference uses the complete form hierarchy beginning with the xfa root node. The advantage of a fully qualified statement is that it will work every time regardless of where the script that contains the reference is written. A fully qualified reference for the exampleButton (Figure 4.16) looks like this:

xfa.form.form1.purchaseOrder.commentsHeader.exampleButton
  1. Select your exampleButton and write the following script in the click event:
    xfa.form.form1.purchaseOrder.commentsHeader.Button3.presence = "invisible";
    
  2. Select Preview PDF, and you will see that the Add Comments button disappears when you click the Example Button.
  3. Go back to Design View and put the same script into the click event of the Add Item button (Button1 in the form hierarchy).
  4. Select Preview PDF, and you will see that the Add Comments button disappears even though the script is running from a different place on the form. This works because you are using a fully qualified object reference.

Abbreviated reference

Even though fully qualified references will always work, they usually take longer to write than abbreviated references. The reference syntax for an abbreviated reference is shorter than a fully qualified reference for one of the following reasons:

  • Relative positioning: You can use an abbreviated reference if two form objects exist in the same container like a subform or a page. For instance, in the purchase order example, the Example Button and the Add Comments button both exist on the commentsHeader subform. You can change your script in the exampleButton's click event to the following abbreviate reference:
    Button3.presence = "invisible";
    

    This works in the exampleButton because of its relative position to the Add Comments button, but it will not work in the Add Item button's click event. In fact, if you put the abbreviated reference at the beginning of the script, not only will this line of script fail, but the entire block of script will not execute. The JavaScript interpreter will not step over an improper statement; it will step out of the routine altogether. If you move the improper abbreviated reference to the end of the code block, you'll see that the previous lines will execute, but the interpreter will still hang on the abbreviated reference.

    You can create a proper abbreviated reference from the Add Item button to the Add Comments button by referring to the first container object that they have in common. For instance, the following script will work from the Add Item button:

    purchaseOrder.commentsHeader.Button3.presence = "invisible";
    
  • Use of shortcuts: FormCalc has built-in shortcuts that reduce the effort required to write references. For instance, the $host shortcut references the host object. Replace the script of your exampleButton with the following line of code:
    $host.messageBox("hello world")
    
    Remember, you need to change the Language to FormCalc. Many more FormCalc shortcuts are documented in the Help System.

The current object

Both FormCalc and JavaScript use shortcuts to refer to the current object. You have already used JavaScript's shortcut "this"; FormCalc's shortcut is the "$" symbol. You can add the following code to the initialize event of your Example Button to customize the tool tip.

JavaScript:

exampleButton::initialize: - (JavaScript, client)
this.assist.toolTip.value = "This is the Example Button";

FormCalc:

exampleButton::initialize: - (FormCalc, client)
$.assist.toolTip.value = "This is the Example Button";

Unnamed objects

I recommend providing meaningful names to your form objects. However, occasionally you may come across unnamed objects in Designer. If you need to refer to an unnamed object in a script, you should precede it with the # sign. Follow these steps to create an unnamed object and properly refer to it with a script:

  1. Create a blank form with the default options including the Print and Email buttons. Set your default scripting language to FormCalc. The page subform is unnamed (Figure 4.17).
    Figure 4.17

    Figure 4.17 The hierarchy of a blank form shows an unnamed subform object.

  2. Select the form1 object at the top of the hierarchy and enter the following script into the initialize event:
    form1::initialize: - (FormCalc, client) --------------------
    xfa.form.form1.#subform.PrintButton1.presence = "invisible"
    
    As you typed the line into the Script Editor, you should have noticed that the unnamed object appeared in the beginning of the statement completion list. All unnamed objects will appear in the beginning of the list and will be preceded by the # symbol.
  3. Select Preview PDF, and you will see that your syntax is correct because the Print button is invisible.
  4. Switch back to Design View and select the form1 object again. This time, switch the Language to JavaScript. When you select Preview PDF, this script will not work because JavaScript cannot correctly interpret the # symbol. When working with unnamed objects in JavaScript, you must use the resolveNode method of the xfa object. The following script will work:
    form1::initialize: - (JavaScript, client) --------------------
    xfa.resolveNode("xfa.form.form1.#subform.PrintButton1").presence = "invisible"
    
    Notice that the reference path that is passed to the resolveNode method is surrounded by quotes.

Multiple objects with the same name

LiveCycle Designer also supports the creation of multiple objects with the same name. When multiple objects have the same name, each has a different occurrence number represented by a number in brackets directly following the object name.

  1. Drag and drop a text field onto your blank form.
  2. Copy and paste the text field a few times, and you will see that Designer puts an occurrence number at the end of each name (Figure 4.18).
    Figure 4.18

    Figure 4.18 You can see the occurrence numbers for your objects in the Hierarchy palette.

    The numbers are zero based so if you have three objects, the highest occurrence number will be two.
  3. Select your form1 object and click the initialize event in the Script Editor.
  4. Switch back to FormCalc and enter the following script:
    xfa.form.form1.#subform.TextField1[0].rawValue = "First"
    xfa.form.form1.#subform.TextField1[1].rawValue = "Second"
    xfa.form.form1.#subform.TextField1[2].rawValue = "Third"
    
  5. Select Preview PDF to see that each of your text fields have a different value.

You will also need to use the xfa.resolveNode method if you are working with multiple objects of the same name because JavaScript cannot interpret the occurrence number syntax. The following code will work in JavaScript:

xfa.resolveNode("xfa.form.form1.#subform.TextField1[0]").rawValue = "First"
xfa.resolveNode("xfa.form.form1.#subform.TextField1[1]").rawValue = "Second"
xfa.resolveNode("xfa.form.form1.#subform.TextField1[2]").rawValue = "Third"

You can find a more advanced example of how occurrence numbers work in the purchase order example. The following script is FormCalc:

// Verify at least one instance of the numAmount field exists.
if (exists(detail[0].numAmount) == 1) then
  Sum(detail[*].numAmount)
endif

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

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

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

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

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

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:

  1. Open the reference document in Acrobat or Reader. This example uses the version 8 document.
  2. Select the "XML Form Object Model DOMs" section under the "Understanding the XML Form Object Model" section.
  3. Select the Host Model and under the Host Model header, select the link titled, "'hostPseudoModel' on page 78."
  4. 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)

  5. 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

    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.

Events

The forms you create in Designer are based on an event-driven programming model. As you have seen in this chapter, the scripts you write are triggered by events. Events are occurrences or actions that change the state of a form. When these events occur, the scripts behind the events are executed. Because this event-driven model determines how your scripts will perform, you need to consider which events to use, when the events will fire, and how often the events will fire. Let's take a look at two examples.

Examples of How Events Work

The following two examples show you important concepts about events. The first example shows you that multiple events fire based on a single action. The second example shows you that some events can be fired multiple times.

One action fires multiple events

Open the multipleEventsFire.pdf form in Designer. Select Preview PDF to see how a single user action can fire multiple events. Even before you click anything, the form rendering and loading is firing multiple events. Once you click on a form object, you will see how even a small action fires multiple events. Experiment with the example and notice the following:

  • The calculate, validate, ready:layout events fire often.
  • The initial form rendering and loading fires the initialize, calculate, validate, ready:form, calculate, validate, ready:layout, and docReady events.
  • Clicking the Button fires the mouseEnter, mouseDown, enter, mouseUp, click, and mouseExit events (Figure 4.25).
    Figure 4.25

    Figure 4.25 Events that are fired when the Button object is clicked.

  • Tabbing out of a Text Field fires the exit event of the Text Field and the enter event of the Drop-down List.
  • Selecting an item in the Drop-down List fires the mouseDown, enter, preOpen, mouseUp, click, and mouseExit events.

An event can fire multiple times

This example uses a simple calculation script on a Numeric Field's calculate event. You will render the form as a print form and as an interactive form, and see how the calculate event fires twice on an interactive form.

  1. Open a blank form in Designer and add a Numeric Field to your form. Set the default value of the Numeric Field to zero. You can set this property on the Value tab of the Object palette.
  2. Select File > Form Properties > Defaults and make sure your preview type is set to Print Form and your default language is set to JavaScript.
  3. Add the following code to the calculate event of the text field:
    NumericField1.rawValue = NumericField1.rawValue + 1;
    
  4. Select Preview PDF. Notice that the value of the Numeric Field is one, so you know that your script executed once and the calculate event fired once.
  5. Go back and change your form's Preview Type to Interactive Form. Select File > Form Properties > Defaults to make this change.
  6. Select Preview PDF. Notice that the value of the Numeric Field is now two. But you didn't change your script. The different result occurred because the calculate event fired twice during the initial rendering of your interactive form. Each time the event fired, the script ran, so your new result is two.

Types of Events

There are three categories of events in XFA forms: process events, interactive events, and application events. Most of your scripts will run in the interactive events but the process and application events will also be useful to you.

Process events

Process events fire automatically based on an internal XFA process or in response to the firing of an interactive event. The following is a list of the process events in XFA forms:

  • calculate
  • form:ready
  • indexChange (introduced in Designer 8)
  • initialize
  • layout:ready
  • validate

As illustrated in Figure 4.26, process events are fired following a major form change like the form merging process and the form layout process.

Figure 4.26

Figure 4.26 The general flow of process events leading up to the PDF form opening in the application. The process events are in bold type. The last event, docReady, is an application event.

Process events are also fired after interactive events are fired. As you saw in the multipleEventsFire.pdf example, a Button click event also fires the layout:ready event for each object on the form. Process events can fire multiple times based on the situation. For instance, in the "An event can fire multiple times" section your calculation script ran twice when you selected Preview PDF. This is because your script ran in the calculate event, which fires twice when an interactive form is opened (Figure 4.26).

Interactive events

Interactive events are very useful for scripting because they fire as a direct result of a user's action. The following is a list of the interactive events in XFA forms:

  • change
  • click
  • enter
  • exit
  • mouseDown
  • mouseEnter
  • mouseUp
  • preOpen

In the example in the "Getting and setting properties" section earlier in this chapter, you saw how you can retrieve the new text and previous text values when something changes in a Drop-down List:

---- order.#subform[0].shirtSize::change: - (JavaScript, client) ---
currentShirtSize.rawValue = xfa.event.newText;
previousShirtSize.rawValue = xfa.event.prevText;

This script runs on the change event of the Drop-down List, which is noted in the header section of the script.

Application events

Application events fire as a result of the actions of a client application like Acrobat or a server application like LiveCycle Forms. The following is a list of the application events in XFA forms:

  • docClose
  • docReady
  • postPrint
  • postSave
  • prePrint
  • preSave
  • preSubmit

As an example, the postPrint event fires immediately after Acrobat or Reader has sent the form to a printer or spooler. You can add the following script to the postPrint event of your form object to provide instructions to the user about mailing or faxing the printed form:

---- form1::postPrint - (JavaScript, client) --------------------------
xfa.host.messageBox("Instruct the user on where to mail or fax the printed form.");

Script Objects

So far, you have put all of your scripts behind form object events like the click event of a button or the initialize event of a text field. This is fine for short scripts that you don't need to reuse. However, when you start creating longer scripts that you can reuse in many different parts of your form, you'll want to write them in a Designer script object.

Script objects reduce your overall scripting efforts and make your forms easier to maintain by putting popular functions into one common location. In many cases, script objects also improve the performance of your forms based on the following two reasons:

  • Scripting code rationalization: You can reduce the overall amount of JavaScript in your form by putting common functions in one location. This reduction decreases the file size of your PDF forms, which results in faster download times.
  • Storage of commonly accessed data: It is very efficient to retrieve a data value from a script object, so you can use script objects to store commonly accessed data values. This improves the performance of forms that connect to external data resources and Web services.

The functions that you write in your script objects can only be written in JavaScript. If your script object is written to Run At Client, the calling script must also be set to Run At Client. The converse is also true. You will also write the calling script in JavaScript.

Creating a Script Object

It is very easy to create a script object; the programming challenge comes when you write the functions of your script object.

  1. Open the formObjectModel.pdf sample file.
  2. One script object called Validation is at the bottom of your Hierarchy palette (Figure 4.27).
    Figure 4.27

    Figure 4.27 The Validation script object in the formObjectModel.pdf file.

  3. To create a new script object, right-click on the order object at the top of your form hierarchy. Select Insert Script Object from the pop-up menu. A new script object appears below the Validation script object. You can create a script object at the form level (as you have done here) or at the subform level. To create a subform level script object, right-click on a subform object instead of the form object.

Writing Functions in Script Objects

After creating a script object, you can then add common functions to it. Select the script object in the Hierarchy palette and click your cursor in the Script Editor palette. There is no limit to the amount of functions that you can add to a script object or the amount of script objects that you can add to a form. You must write your functions according to the syntax and rules of JavaScript.

The Validation script object on the form provides common date validations that test any date entry on your form in a variety of ways including:

  • Testing for real dates: A variety of tests can ascertain that a date entry is for a date that actually exists. These tests include logic that accounts for different month lengths and for leap years.
  • Testing for future dates: These tests are valuable for birth date entries; you may not want to accept a birth date value that has not yet occurred.
  • Testing for past dates: These tests are valuable for shipping date entries; you do not want to accept a ship date that has already past. The warehouse team would find this request to be rather challenging.

The Validation script object contains 216 lines of JavaScript, so you wouldn't want to replicate this in each Date/Time Field object on your form. The script object is organized into five functions that work together. The main function, dateValidation, calls each of the other functions. The following code shows the snippet of the dateValidation function that references the other functions.

function dateValidation(field, type){
[..]
   flagYear = checkYear(nYear, currYear, field, type);
   flagMonth = checkMonth(nMonth, currMonth, flagYear, field, type);
   flagDay = checkDay(flagYear, flagMonth, nDay, nMonth, leapYear, field, type);
   compareDay(flagDay, flagMonth, flagYear, nDay, currDay, field, type);
[..]
}

Referencing Functions in Script Objects

Now that you have an effective date Validation object, you just need to call it from the Date/Time objects on your form. Select the orderDate object on your form and go to the Script Editor. The script for calling the Validation script object is located in the exit event of the field:

Validation.dateValidation(this,2);

You reference script objects just like you reference other Designer objects by using a dot to indicate different levels of hierarchy. The first item is the script object (Validation) and the second item is the function (dateValidation). The function takes two parameters, which are in parentheses.

In this case, you pass two arguments to the script object. The first argument is the object that you are testing. The "this" keyword indicates that you will test the orderDate object. The second argument indicates the "type," which is represented by an integer value between 0 and 2. The type descriptions can be found at the top of the script object:

if type = 0 then any date can be entered as long as it is real
if type = 1 then no future dates can be entered, only real dates allowed
if type = 2 then no past dates can be entered, only real dates allowed

Debugging Scripts

The debugging tools in Designer keep improving with each version. If you come from a programming background, you may find that these tools are not yet on the level of the debugging tools in IDEs (integrated development environments) like Microsoft's Visual Studio. However, Designer does provide the following features and tools to help you track down problems with your forms and scripts.

The Warnings Tab of the Report Palette

The Warnings tab of the Report palette should be the first place you go to examine the behavior of your form. Designer logs useful information about your form to the Warnings tab when you save your file or when you select Preview PDF. The important information includes missing font information and missing image information (Figure 4.28).

Figure 4.28

Figure 4.28 The Warnings tab shows that the form has a missing image. You can clear the warning messages by selecting Clear Warnings from the Report menu.

Syntax checking

In Designer ES, the Warnings tab also displays some scripting syntax errors. You can test the syntax of your scripts by clicking the Check Script Syntax icon in the Script Editor. For instance, in the script illustrated in Figure 4.29, Designer highlights the syntax error in the Script Editor and also provides the following description on the Warnings tab:

Error: Too many closing braces, Line:9
Figure 4.29

Figure 4.29 The syntax checking feature of Designer ES highlights the extra closing brace in the script.

Target versioning

If you are working in Designer ES, you can target a form to a specific version of Acrobat or Reader. If you use a feature in Designer ES that is not available in your targeted client application, you will receive a warning message and a description of the incompatibility on the Warnings tab.

For instance, you can set your form's target version to "Acrobat and Adobe Reader 7.0.5 or later" on the Defaults tab of the Form Properties dialog box (Figure 4.30).

Figure 4.30

Figure 4.30 The Target Version setting in the Form Properties dialog box of Designer ES.

Now select the Duplex Flip Long Edge option on the PDF Print Options tab of your Form Properties dialog box. Because this is a printing feature that only became available in LiveCycle ES, it will not be compatible with your target version of Acrobat and Reader 7.0.5. Designer will display the following message on the Warnings tab:

The PDF Print Options selected in Form Properties require the form be saved as Acrobat 8.1 or later.

The JavaScript Debugger

Another useful tool for debugging your scripts is the JavaScript Debugger that is included with Adobe Acrobat Professional. To enable the JavaScript debugger for LiveCycle Designer, you must first enable JavaScript and the JavaScript debugger in Acrobat Professional:

  1. Launch Acrobat Professional and select Edit > Preferences.
  2. Select JavaScript from the list on the left.
  3. Select Enable Acrobat JavaScript if it is not already selected.
  4. On the JavaScript Debugger panel, select "Enable JavaScript debugger after Acrobat is restarted."
  5. Select "Enable interactive console."
  6. Select "Show console on errors and messages."
  7. Click OK to close the Preferences dialog box.
  8. Quit Acrobat Professional.
  9. In LiveCycle Designer, click the Preview PDF tab.
  10. Press Ctrl+J to open the JavaScript Debugger.

Once enabled, the JavaScript Debugger automatically pops up at runtime when an erroneous script is executed (Figure 4.31). In cases where you would like the debugger to be open before running any scripts, you can also press Ctrl+J at runtime to open the debugger.

Figure 4.31

Figure 4.31 The JavaScript Debugger launches when there is a problematic script.

The debugger displays information about what went wrong including the full path of the field containing the erroneous script, the event where the script is located, the line number of the script, and a basic explanation of the error.

The Message Box Method

A practical and useful method of tracking your script's performance at runtime is to use the messageBox method of the host object. The trick is to position your messageBox script at the appropriate point during runtime to retrieve the information you need. For a hypothetical example of using the messageBox method for debugging, open the dataDOM.pdf file from the Samples folder.

In a previous example, you used the buttons on this form to cycle through a series of colors on a Rectangle object. But what if you ran this form and the rectangle did not change colors when you clicked the Next button (Figure 4.32)?

Figure 4.32

Figure 4.32 If the Next button does not produce a color change, you need to debug your form.

A good place to start debugging this problem is to see if the color value is changing when the Next button is clicked. You can check this value at runtime by adding a messageBox to the appropriate spot in your script:

if (xfa.dataWindow.recordsAfter > 0) {
   xfa.dataWindow.moveCurrentRecord(1);
   xfa.host.messageBox("The color is: " + entry.shirtColor.rawValue, "Debugging", 3)
}
else {
   app.alert("This is the last record in the data file.");

This script produces the messageBox shown in Figure 4.33, which indicates that your script is retrieving a new color value each time the Next button is clicked. The problem must lie elsewhere.

Figure 4.33

Figure 4.33 The messageBox proves that your script is receiving a new color value at runtime.

You can also use the JavaScript app alert method to display message boxes at runtime:

app.alert(variable);

Moving On...

Now that you are a scripting expert, you will learn how to apply scripting and other techniques to control, modify, and validate your form's data.