Validation Patterns: Part 3

Here is the last (for now) in the series on how to validate templates in a user-friendly manner.  I have attached a new and improved sample (with data).

What is new in this version:

  • An email submit button that becomes active only when there are no errors on the form
  • A listbox field that shows all the errors on the field.  When you enter into the list field, the field corresponding to the error gets highlighted.  Try selecting different elements in the list.

But more importantly, this sample form now holds a toolkit of functions that allow you to take control of the way Reader validates form fields.

Behind the scenes on the script side, there is a fair bit more in the toolbox.  My goal is that you can re-used these script objects in your forms and keep your form designs as clean and simple as possible.  If you look at the form you will see that the vast majority of script is inside the script objects.  The fields and subforms on the form itself have minimal amounts of script.

An added benefit of following this particular form development methodology is that is should be very consistent with future enhancements we add to XFA and Reader.

Here is a summary of the script functions that you can use in your form development:

/**
* setStatus(vContainer, vStatus)
* Call this method as the last line of your validation script.
* This function does two things:
* 1) highlights or resets the field according to whether it is valid or not
* 2) If invalid, logs the error
*
* @param vContainer — the container we are validating. 
*                      If a subform, process recursively.
* @param validStatus — true | false
* @return the status for the validation script to use 
*         (for now hardcoded to "true")
*/

/**
* formHasErrors()
*   Useful for changing the state of form objects depending on if there are
*   validation errors or not.
*   Place this call inside a validation or calculation script and make sure
*   you have called registerListener(this) from your initialization event.
* @return true if there are errors.  False otherwise.
*/

/**
* registerListener(vListener)
*   Call this from you initialization event if you want to be able to
*   call formHasErrors() in your calculation or validation events.
* @param vListener — The object that cares about whether there are errors. 
*   We’ll keep track of all the listeners. Every time a field changes valid
*   state (becomes valid or invalid), we will loop through all listeners and
*   force their calculate and validate scripts to run.
*   If a listener is a choiceList object, we’ll synchronize the choicelist
*   entries with field errors.
*   When a choicelist has zero entries, we hide it.
* @return void
*/

/*
* setFieldMandatory(vObject, vMandatoryState, vForce)
*   Mark a field or exclusion group as being mandatory.
*   When calling this from a validation script,
*   be sure to also call setStatus()
*
* @param vObject — the field or exclusion group that we’re marking
* @param vMandatoryState — true or false 
* @return boolean — true if the state changed
*/

/**
* clearErrList()
* Call this method before removing a subform or re-ordering subforms.
* Our tracking is based on storing SOM expressions.
*
The SOM expression for a field can change if the order of its parent
* subform changes. 
* After clearing the list and removing/moving subforms,
* call xfa.form.execValidate() to rebuild the list.
* Note that it is not necessary to call this method when appending new subforms.
*/

Then there are a couple of methods you might choose to modify for your own use — in case you do not like the way the sample highlights invalid fields:

/** 
* highlight(vObject)
*   Highlight a field (or exclusion group or subform) to indicate that it
*   has a validation error
* @param vObject — the subform/field/exclusion group to highlight
*/

/**
* unhighlight(object)
*   reset the form field/subform/exclusion group to the state it was in
*   the template.
* @param object — the subform/field/exclusion group to highlight
*/

 

The one thing that does not work back to Reader 7 is the button script that sets focus on an error field.  xfa.host.setFocus() came later.

But the rest of script functionality should work fine in Reader 7. The hardest part about making the scripts work in Reader 7 was that the convenience methods for manipulating choice lists are not available there.  The script has to manipulate the XML structures directly.