Section 10.7.  Using scripts for validation

Prev don't be afraid of buying books Next

10.7. Using scripts for validation

One of the most common uses for scripts is to perform validation, either because custom error messages are desired, or because the validation involves complex business rules. In this section we will look at three different examples of validation scripts. In the process, we will learn more about JScript as well as the InfoPath object model. All of the examples in this chapter can be found in the order_scripts.xsn example file. This form, shown in Figure 10-7, is a slightly modified version of our order form from the previous chapter.

Figure 10-7. Revised Order Form (order_scripts.xsn)




10.7.1 Validation-related events

Validation is usually associated with either the OnBeforeChange event or the OnValidate event.

OnBeforeChange

The OnBeforeChange event occurs after the user has made a change to a value, but before the change is accepted. If there is an error in the value, the change will be undone and the field will return to its previous value. This is useful if you want to prevent a user from specifying a field unless another field is specified or has a certain value. For example, you may want to prevent the user from specifying a second address line unless the first address line is completed.

OnValidate

The OnValidate event occurs after the user has changed the value in the field, and after it has been validated against the schema. If an error is reported, the change will stay, but the field will be underlined in red to identify it as an error.

In addition to these events, it is possible to perform some validation when the user submits the form by relating the script to the OnSubmitRequest event. However, the user will not be warned of the error until the form is completed. Also, this works only for submit, not save. As a result, a user may unknowingly save a document with errors in it.

10.7.2 Launching Script Editor

To create or modify a script function associated with validation, you can launch Script Editor from the field's Data Validation dialog. If a script function already exists for that field, for that event, the cursor will be positioned at that script function. If one does not exist, a stub will be created, as we saw in our previous example.

To launch Script Editor to show our first example:

1. Open order_scripts.xsn in design mode.

2. Right-click the Product Number field and click Text Box Properties.

3. On the Data tab, click Data Validation. This brings up the Data Validation dialog shown in Figure 10-8.

Figure 10-8. The Data Validation dialog




4. At the bottom of the Data Validation dialog, select the event you wish to use as a trigger for the script, in this case OnValidate, and click Edit to launch Script Editor.

10.7.3 A simple validation function

You should now be in Script Editor with your cursor positioned on the first line of the script shown in Example 10-1. The purpose of this script is to ensure that the product number is less than 1000. This validation could also be done without a script, but we have chosen a simple example to start with.

Example 10-1. Product number validation
 function msoxd__item_number_attr::OnValidate(eventObj) {   // Make sure it is less than 1000   if (eventObj.Site.nodeTypedValue > 999)     eventObj.ReportError(eventObj.Site,        "Invalid product number: " +        eventObj.Site.nodeTypedValue +        "  The product number must be less than 1000.") } 

Line 1 indicates that the name of the function is msoxd__item_number_attr::OnValidate, which means that it is associated with the item number field and the OnValidate event. The function name is fixed and cannot be changed. Line 1 also tells us that a single parameter is passed to this function, eventObj. It provides information about the event, in particular the node that changed to trigger it (eventObj.Site).

Line 4 starts an if statement that determines whether the value in question is over 999. The value of the appropriate field is retrieved using the reference eventObj.Site.nodeTypedValue. If the value is greater than 999, an error is reported using the ReportError method of eventObj. We pass two parameters to the ReportError method: the node that is in error (eventObj.Site), and a string that is the error message.

You can test this script by entering a product number that is greater than 999. The field will be surrounded with a red-dashed line, and the custom error message will appear both when you hover over the field and when you right-click it.

10.7.4 Validation involving multiple values

Our last example simply checked the value of a field against a constant. However, some validation involves multiple fields. Suppose, for example, that the product number 999 is used for special promotions that have a limit of one per customer per order. As such, we don't want a user to be able to enter a quantity that is greater than 1 if the product number is 999. The script shown in Example 10-2 will enforce this constraint.

Example 10-2. Multi-field validation
 function msoxd_ns1_item::OnValidate(eventObj) {   // Retrieve the necessary nodes and values   var itemNode = eventObj.Site   var quantNode = itemNode.selectSingleNode("ns1:quant")   var quant = quantNode.nodeTypedValue   var prodNum = itemNode.selectSingleNode("@number").nodeTypedValue   //test the condition and report error   if (prodNum == 999 && quant > 1)     eventObj.ReportError(quantNode,      "Quantity cannot exceed 1 for product number 999.", false) } 

If you are still in Script Editor, you can simply scroll down to find this function. However, if you are not, you will have to launch Script Editor in a different way to get to it directly. This function is related to the entire item row, rather than an individual field. Specifically, it is associated with the item element. To get to a script function for an element that is not represented by one field in the form:

1. Select item in the Data Source task pane.

2. Right-click it and click Properties.

3. Click the Validation and Script tab.

4. As before, select the event you wish to use as a trigger for the script, in this case OnValidate, and click Edit to launch Script Editor.

In our previous example, we used the reference eventObj.Site.nodeTypedValue to get to the value of the element we were validating. In this case, we instead want to work with nodes that are related to the element we are validating, namely the quant child and the number attribute of the item element.

line 4

On line 4, we assign the item element to a variable, namely itemNode.

line 5

On line 5, we assign the quant node using the selectSingleNode method of itemNode. The selectSingleNode method is passed an XPath expression which selects the desired node. In our case, we are using a relative XPath expression to select the ns1:quant child of the item element. It is also possible to use absolute XPath expressions, as we will see in our next example. Note that the namespace prefix is required when referring to qualified elements like quant. The prefix ns1 is generated by InfoPath. If you scroll to the top of the script file, you will see the line that maps the ns1 prefix to the appropriate namespace (see Example 10-3).

Example 10-3. Declaring prefixes for namespaces
 XDocument.DOM.setProperty("SelectionNamespaces",           'xmlns:ns1="http://xmlinoffice.com/orders"            xmlns:xhtml="http://www.w3.org/1999/xhtml"'); 

line 6

On line 6 we extract the typed value of the node and assign it to the quant variable. Using a typed value allows it to be treated as a number rather than as a string. It would also be possible to specify quantNode.text to return the content of the quant element as a string.

line 7

Line 7 retrieves the product number value in a similar fashion to the quant child. However, since the number node is an attribute rather than an element, the @ character is used in the XPath expression to indicate this. In addition, the number attribute is unqualified, so it is not prefixed in the expression.

lines 9 through 12

Lines 9 through 12 test for the error condition and report an error if necessary. Note that the first parameter passed to the ReportError method is the quantNode node. This means that the error will show up as an error in the quantity field, even though the error involves two fields. If desired, we could have specified the product number field, or called ReportError twice to report errors in both fields.

In this example, we could have associated the script function with the quantity field, rather than the entire row. However, associating it with the entire row, i.e. the item element, allows the script function to be executed each time any field in the row is changed.

10.7.5 The OnBeforeChange event

Up to this point, we have associated both of our validation examples with the OnValidate event. It is also possible to use the OnBeforeChange event for validation. For example, suppose we want to prevent users from entering a second address line if the first address line is not completed. We might use a script like the one shown in Example 10-4.

Example 10-4. Using the OnBeforeChange event
 function msoxd_ns1_addr2::OnBeforeChange(eventObj) {   // Retrieve the necessary nodes and values   var addr1 = XDocument.DOM.selectSingleNode(                   "/ns1:order/ns1:shipTo/ns1:addr")   var addr2 = XDocument.DOM.selectSingleNode(                   "/ns1:order/ns1:shipTo/ns1:addr2")   //test the condition and report error   if (addr1.text == "" && addr2.text != "")   {     eventObj.ReturnMessage =       "A second address line cannot be specified without a first."     eventObj.ReturnStatus = false     return   }   eventObj.ReturnStatus = true   return } 

This script handles the error slightly differently, because calling the ReportError function is not allowed from an OnBeforeChange script function. Instead, it calls the ReturnMessage method of eventObj if there is an error. This results in a dialog that displays the error message after an invalid value is entered. In addition, the function sets the ReturnStatus property of eventObj to false if there is an error, and true if there is not an error.

If there is an error, the change to the field will be rolled back. You can test this by attempting to enter a second address line when the first address line is not specified. When you try to move the cursor from the Address 2 field, you will get an error message and your change will be undone. Interestingly, because the function is related to the addr2 element only, this script does not prevent you from entering a first address line, then a second line, then deleting the first line. To do that, you would need to associate the script with a higher-level element, such as shipTo, which would be executed any time a change was made in any of its children.

There is another difference between this example and the previous examples. It uses absolute XPath expressions rather than relative ones. In the last example, we called the selectSingleNode method of the item node. The XPath expression we used was evaluated in the context of the item node. In this case, we are also executing the selectSingleNode method, but of the XDocument.DOM object itself, which represents the entire document. As a result, we need to specify the entire path to retrieve the node of interest, namely: /ns1:order/ns1:shipTo/ns1:addr

The slash at the beginning of the expression means that it starts at the root of the document and works its way down the hierarchy.

Amazon


XML in Office 2003. Information Sharing with Desktop XML
XML in Office 2003: Information Sharing with Desktop XML
ISBN: 013142193X
EAN: 2147483647
Year: 2003
Pages: 176

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net