Introduction to Validation
Validation of form fields is an important part of any user
interface. Validation can prevent users from entering incorrect
or malformed data, enforce required fields, thwart potential
buffer overflows, or perform more complicated checks to
guarantee the data is well-formed before it is used in an
operation.
WDK 5 Validation Framework
Because almost all forms require validation time is often wasted
by hand-coding validation into each application. Fortunately,
form validation can be generalized and re-applied as needed.
WDK 5 introduced a validation framework that provides
declarative support for typical user validation tasks, is
extensible through “plug-in” validation, and offers data
dictionary integration.
In the WDK 5 validation framework, a validator is a control that
checks one or more input controls for a specific type of error
condition and displays a description of the problem if an error
is found. It is common for more than one validator control to be
used against each input control.
Disabling Validation
If validation is turned on it will be initiated in the form
processor prior to a server-side action event being handled.
Validation is on by default; however, it may be disabled by setting
the <dmf:webform> element’s validation
attribute to false. Disabling validation may be
necessary if it is slowing down the UI redraw or if you don’t
need validation on all events. Even when disabled you may
explicitly call the validate() method in your component
to run all the validators or write a custom routine to selectively
execute one or more validators.
Manual Validation
Manual validation of the controls on the page is still possible
using a mixture of javascript and HTML for client-side validation,
or Java for server-side validation. Because these specialized
one-off validators have limited use and no standardized way of
delivering error messages back to the user, using the WDK 5
validation framework is strongly recommended.
Overview of Existing Validators
The WDK validation framework provides ten generic validation
controls. Each validator is associated to an input controls and
configured by setting the validator’s tag attributes in the JSP
page.
The validation tag definitions can be found in the
dmform tag library definition (tld), while the
Control and ControlTag class for each
of these validators can be found in the
com.documentum.web.form.control.validator package.
If the value of the control to validate is a null or empty value, the
control is assumed to be valid. The exception to this rule is the
required field validator. Therefore, it is often useful to combine
the required field validator with other validators to ensure a valid
value is provided.
The tag attributes below are common for each of the validation
control tags (not including the validation summary tag).
Common Validator Tag Attributes
- name (required) – the name of the validation control
- controltovalidate (required) – the name of the input control to be validated
- enabled – the validator is enabled by default, but set this attribute to false to disable the validator, or true to explicity enable the validator
- nlsid – the nlsid of the internationalized error message to display if the control to validate does not pass validation
- errormessage – the error message to display if the control to validate does not pass validation; the nlsid attribute takes precedence over this attribute
- visible – by default the validator will display an error message when validation fails; set this attribute to false to prevent the validator from outputting an error message (useful if using the validationsummary tag)
- style – the (css) style properties for the validator error message
- cssclass – the css class to apply to the validator error message
- id – this attribute is not used
Compare Validator
The compare validator verifies that the input control value passes
evaluation with the specified operator and comparison value. The
comparison value may either be the value specified by the
comparevalue attribute or the value of the input
control identified by the comparecontrol attribute.
Example
<dmf:password name="password" size="10"/>
<dmf:password name="password_confirm" size="10"/>
<dmf:comparevalidator
name="val_compare_password"
controltovalidate="password"
comparecontrol="password_confirm"
errormessage="The passwords do not match."
type="string"
operator="equal"/>
Tag Attributes
- type – determines the way the fields are compared; valid values are string (default) and integer
- operator – the condition to apply to the control to validate value and the comparison value; valid values are equal (default), notequal, greaterthan, greaterthanequal, lessthan, and lessthanequal
- comparevalue – the value which is compared to the value of the control to validate
- comparecontrol – the input control whose value is compared to the value of the control to validate
Date Validator
The date validator is used to validate a dmf:dateinput
control. The validation will not pass unless the submitted value
is a valid date.
Example
<dmf:dateinput name="birthday"/>
<dmf:datevalidator
name="val_date_birthday"
controltovalidate="birthday"
errormessage="Bad date entered."/>
Date Time Validator
The date time validator is used to validate a dmf:datetime
control. The validation will not pass unless the submitted value
is a valid date and time.
Example
<dmf:datetime name="appointment"/>
<dmf:datetimevalidator
name="val_datetime_appointment"
controltovalidate="appointment"
errormessage="Bad date/time.."/>
Input Mask Validator
The input mask validator verifies that the value of the control to
validate matches a pattern of characters. This validator is similar
to the regular expression validator; however, a much simpler pattern
may be used (same as Content Server masks).
Example
<dmf:text name="ssn" size="12"/>
<dmf:inputmaskvalidator
name="val_mask_ssn"
controltovalidate="ssn"
errormessage="Must be in the format nnn-nnn-nnnn."
inputmask="###-###-####"/>
Tag Attributes
- inputmask – the pattern to test against
The inputmask attribute accepts a string of characters
with the notations below. To escape a masked character for use as a
literal member of the mask string, use a double backslash () before
the character.
Mask Notation
- # – numeric characters
- & – all characters
- A – alphanumeric characters only
- ? – alphabetic characters only
- U – uppercase alphabetic characters only
- L – lowercase alphabetic characters only
Multi-values Input Mask Validator
The multi-values input mask validator validates multiple values in a
dmf:label control using an input mask and a separator
character. See the mask notation in the input mask validator for
valid characters to use in the inputmask attribute.
Example
<dmf:label name="zipcodes" label="<%= zipcodes.join(",") %>" />
<dmf:multivaluesinputmaskvalidator
name="val_multivaluesmask_zipcodes"
controltovalidate="zipcodes"
errormessage="One or more zipcodes are invalid."
inputmask="#####"
separator=","/>
Tag Attributes
- inputmask– the pattern to test against
- separator – the character used to delimit the input values
Multi-values Required Field Validator
The multi-values required field validator validates that all of the
required values in a dmf:listbox control have been
set.
Example
<dmf:datalistbox name='types' size='5'
query="select r_object_id, name from dm_type">
<dmf:dataoptionlist>
<dmf:option datafield="r_object_id" labeldatafield="name"/>
</dmf:dataoptionlist>
</dmf:datalistbox>
<dmf:multivaluesrequiredfieldvalidator
name="val_multivaluesrequired_types"
controltovalidate="datalistbox_click"
errormessage="One or more options in the list are invalid."
indicatorstyle="color:red;
indicator="*" />
Tag Attributes
- indicator – the string which represents a required field
- indicatornlsid – the nlsid of the internationalized string which represents a required field
- indicatorstyle – the (css) style properties for the indicator string
- indicatorcssclass – the css class to apply to the indicator string
Range Validator
The range validator will test that the value of the control to
validate falls within the specified range(s). The upper and
lower ranges (both are optional) may either be the value specified
by the minvalue and maxvalue attributes
or the value of the input controls identified by the
minvaluecontrol and maxvaluecontrol
attributes.
Example
<dmf:text name="quantity" size="1"/>
<dmf:rangevalidator
name="val_range_quantity"
controltovalidate="quantity"
errormessage="Please enter a quantity from 1-5."
minvalue="1"
maxvalue="5"/>
Tag Attributes
- type – determines the way the fields are compared; valid values are string (default, lexicographical range) and integer
- minvalue – the minimum valid value
- minvaluecontrol – the control containing the minimum valid value
- maxvalue – the maximum valid value
- maxvaluecontrol – the control containing the maximum valid value
Regular Expression Validator
The regular expression validator will test the regex specified by
the expression attribute against the value of the control
to validate. Regular expression complexity aside, this validator can
be tricky to use because the expression applied must encompass the
entire value which is being tested.
For example, if the expression is abc and the value
tested is aabcc the validator will indicate an error.
Should this be a validation error even though a match (in the very
middle of the string) can be identified?
It seems as if the supplied expression is being interpreted as
^abc$. The workaround could be to change the expression
to .*abc.*, but regular expression veterans will likely
be reluctant to use such a heavy-handed technique.
Example
<dmf:text name="username" size="40"/>
<dmf:requiredfieldvalidator
name="val_regexp_username"
controltovalidate="username"
errormessage="User names are alphanumeric, with no spaces."
expression="[a-zA-Z0-9]+"/>
Tag Attributes
- expression (required) – the regular expression (org.apache.regexp.RE) to apply
Required Field Validator
The required field validator verifies that the input control to
validate is not null or empty. Pair this validator with the
validators to override their default behavior which passes validation
of an input control if a null or empty value is supplied.
Example
<dmf:text name="username" size="40"/>
<dmf:requiredfieldvalidator
name="val_required_username"
controltovalidate="username"
errormessage="Username is a required field."
indicatorstyle="color:red;
indicator="*" />
Tag Attributes
- indicator – the string which represents a required field
- indicatornlsid – the nlsid of the internationalized string which represents a required field
- indicatorstyle – the (css) style properties for the indicator string
- indicatorcssclass – the css class to apply to the indicator string
Validation Summary
The validation summary renders an ordered list of messages for failed
validators in the form. Although it groups all the error messages in
one place it does not suppress the output of the error messages by
each of the validators on the page. To do that, you must set the
visible attribute of each validation control to
false.
This tag does have two drawbacks. First, the messages must be
displayed in an ordered list; there is no way to control the layout
of the error messages. Second, the markup for the ordered list is
present even if there are no errors. The presence of this markup
(in the form of <ol> ... </ol> tags)
leaves whitespace
on the page where the error messages would have appeared.
Example
<dmf:validationsummary header="Please fix the errors below:"/>
Tag Attributes
- nlsid – the nlsid of the internationalized error message to display if the control to validate does not pass validation
- style – the (css) style properties for the validator error message
- cssclass – the css class to apply to the validator error message
- id – this attribute is not used
- header – the text to display above the list of error messages
Client Side Validation
Client-side validation saves time and valuable network resources by
validating form fields in the client browser before the form is
submitted to the server. The user is immediately alerted to the
problematic fields without waiting for a response from the server.
Using a mix of javascript, css, and DHTML each of the above validators
could easily include a client-side counterpart. The trick to
developing any client-side validator is ensuring cross-browser
compatibility. Fortunately, there are many examples of
browser-compatible validation code available on the internet.
While client-side validation is not a substitute for server-side
validation, it can play an important role in improving the
responsiveness of the UI and freeing up precious server resources.
In the next section I will include a client-side validation
counterpart in the custom validator.
Writing a Custom Validator
The WDK 5.3 dmf:listbox tag implementation adds a
multiselect attribute. This attribute allows users to
select multiple items from the list. With the ability to select
multiple items comes a need to limit users to a maximum number of
selected items. Meet the list box select limit validator.
List Box Select Limit Validator
The list box select limit validator restricts the number of selected
items in a multiselect list box control. Limit the maximum number of
selectable items using the validator’s maxselected
attribute.
Two additional attributes are optional. Enable client-side javascript
by setting the validateatclient attribute to true.
To display a javascript error message each time the user selects too
many items set the displayclientalert attribute to
true.
By extending com.documentum.web.form.control.validator.BaseValidator
and including the common validator tag attributes, the custom
validator displays internationalized messages both at the client and
the server. BaseValidator extends
com.documentum.web.form.control.Label and implements
com.documentum.web.form.control.validator.IValidator, the
mandatory validator interface.
If enabled, the client-side validator is initialized when the page first
loads, and runs each time the list box control’s set of selected items
changes. The initialization sets the onchange attribute of
the list box control’s select HTML element to a function
which keeps the last good set of selected options. If new selection ever
exceeds the maximum number selectable options, the selection is
invalidated and reverted the to the previous good selection.
The server-side validator implementation fetches from the Request object
the array of parameter values for the control to validate. If the array
length is larger than the maximum number of values, the validator fails.
Example
<dmf:listbox name="colors" size="7" multiselect="true">
<dmf:option value="1" label="Red"/>
<dmf:option value="2" label="Orange"/>
<dmf:option value="3" label="Yellow"/>
<dmf:option value="4" label="Green"/>
<dmf:option value="5" label="Blue"/>
<dmf:option value="6" label="Indigo"/>
<dmf:option value="7" label="Violet"/>
</dmf:listbox>
<bfval:listboxselectlimitvalidator
name="val_limitselection_colors"
controltovalidate="colors"
errormessage="You can't select more than three options."/>
maxselected="3"
validateatclient="true"
displayclientalert="true"
Tag Attributes
- maxselected – the maximum number of items to from the list
- validateatclient – whether to use javascript to validate the field before the form is posted to the server
- displayclientalert – if validateatclient is true, this flag toggles whether to alert the user each time they have selected too many items from the list
List Box Select Limit Validator Tag Library Definition
<!–
– Copyright (c) ArgonDigital 1996-2004. All rights reserved.
–>
<tag>
<name>listboxselectlimitvalidator</name>
<tagclass>com.ArgonDigitalgroup.wdk.validator.ListBoxSelectLimitValidatorTag</tagclass>
<bodycontent>empty</bodycontent>
<!-- Unique Validator Attributes -->
<attribute>
<name>maxselected</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>validateatclient</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>displayclientalert</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- Common Validator Attributes -->
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>controltovalidate</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>enabled</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>nlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>errormessage</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>visible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>style</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssclass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
List Box Select Limit Validator Control
/**
* Copyright (c) ArgonDigital 1996-2004. All rights reserved.
*/
package com.ArgonDigitalgroup.wdk.validator;
import com.documentum.web.form.control.ListBox;
import com.documentum.web.form.control.validator.BaseValidator;
/**
* Validator implementation limits the number of selected options in a
* multiselect list box control.
*/
public class ListBoxSelectLimitValidator extends BaseValidator {
/** the max number of selected options */
private int mMaxSelected = 0;
/** whether to enable client-side validation */
private boolean mValidateAtClient = false;
/** whether to display an alert in the client side validation */
private boolean mDisplayClientAlert = false;
/**
* Gets the maximum number of selected options.
*
* @return the max number of selected options
*/
public int getMaxSelected() {
return mMaxSelected;
}
/**
* Sets the maximum number of selected options.
*
* @param max number of selected options
*/
public void setMaxSelected(int maxSelected) {
mMaxSelected = maxSelected;
}
/**
* Gets whether to use client-side validation javascript.
*
* @return whether to use client-side validation javascript
*/
public boolean getValidateAtClient() {
return mValidateAtClient;
}
/**
* Sets whether to use client-side validation javascript.
*
* @param validateAtClient whether to use client-side validation
*/
public void setValidateAtClient(boolean validateAtClient) {
mValidateAtClient = validateAtClient;
}
/**
* Gets whether to display an alert in the client side validation.
*
* @return whether to display an alert in the client side validation
*/
public boolean getDisplayClientAlert() {
return mDisplayClientAlert;
}
/**
* Sets whether to display an alert in the client side validation.
*
* @param displayClientAlert whether to display an alert
*/
public void setDisplayClientAlert(boolean displayClientAlert) {
mDisplayClientAlert = displayClientAlert;
}
/**
* Returns true if the control is a listbox whose number of selected
* items is below the set limit, and false otherwise.
*
* @return boolean true if the listbox item count is below the limit
*/
protected boolean doValidate() {
boolean isValid = false;
Control control = getControlToValidate();
if ( control instanceof ListBox ) {
String[] selectedOptions = getPageContext().getRequest()
.getParameterValues(control.getElementName());
isValid = (selectedOptions != null) &&
(selectedOptions.length <= mMaxSelected);
}
return isValid;
}
}
List Box Select Limit Validator Control Tag
/**
* Copyright (c) ArgonDigital 1996-2004. All rights reserved.
*/
package com.ArgonDigitalgroup.wdk.validator;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import com.documentum.web.form.Control;
import com.documentum.web.form.control.validator.BaseValidatorTag;
import com.documentum.web.util.StringUtil;
/**
* Validator tag implementation limits the number of selected options in a
* multiselect list box control.
*/
public class ListBoxSelectLimitValidatorTag extends BaseValidatorTag {
/** the max number of selected options */
private Integer mMaxSelected = null;
/** whether to enable client-side validation */
private Boolean mValidateAtClient = null;
/** whether to display an alert in the client side validation */
private Boolean mDisplayClientAlert = null;
/**
* Set the maximum number of selected options.
*
* @param max number of selected options
*/
public void setMaxselected(int maxSelected) {
mMaxSelected = new Integer(maxSelected);
}
/**
* Sets whether to use client-side validation javascript.
*
* @param validateAtClient whether to use client-side validation
*/
public void setValidateatclient(boolean validateAtClient) {
mValidateAtClient = new Boolean(validateAtClient);
}
/**
* Sets whether to display an alert in the client side validation.
*
* @param whether to display an alert in the client side validation
*/
public void setDisplayclientalert(boolean displayClientAlert) {
mDisplayClientAlert = new Boolean(displayClientAlert);
}
/**
* Release the tag state
*/
public void release() {
mMaxSelected = null;
mValidateAtClient = null;
mDisplayClientAlert = null;
}
/**
* Get the control class.
*
* @return the class of control to create
*/
protected Class getControlClass() {
return ListBoxSelectLimitValidator.class;
}
/**
* Set the control properties.
*
* @param control the control instance
*/
protected void setControlProperties(Control control) {
super.setControlProperties(control);
ListBoxSelectLimitValidator val = (ListBoxSelectLimitValidator) control;
// Set control properties from the tag arguments
if (mMaxSelected != null) {
val.setMaxSelected(mMaxSelected.intValue());
}
if (mValidateAtClient != null) {
val.setValidateAtClient(mValidateAtClient.booleanValue());
}
if (mDisplayClientAlert != null) {
val.setDisplayClientAlert(mDisplayClientAlert.booleanValue());
}
}
/**
* Render the control HTML.
*
* @param out the jsp writer
* @throws IOException if an exception occurs
*/
protected void renderEnd(JspWriter out) throws IOException {
ListBoxSelectLimitValidator val = (ListBoxSelectLimitValidator) getControl();
if (val.isVisible() && val.getValidateAtClient()) {
renderClientSideValidation(out);
}
super.renderEnd(out);
}
/**
* Render the client-side validation JavaScript.
*
* @param out the jsp writer
* @throws IOException if an exception occurs
*/
protected void renderClientSideValidation(JspWriter out) throws IOException {
ListBoxSelectLimitValidator val = (ListBoxSelectLimitValidator) getControl();
StringBuffer buf = new StringBuffer();
String errorMessage = StringUtil.escape(StringUtil.escape(val.getLabel(), ''), ''');
String controlName = val.getControlToValidate().getElementName();
boolean displayAlert = val.getDisplayClientAlert();
int max = val.getMaxSelected();
buf.append("n<script language='javascript'>n");
buf.append(" var dropDownList = null;n");
buf.append(" var dropDownLists = document.getElementsByTagName('SELECT');n");
buf.append(" for ( var i = 0; i < dropDownLists.length && !dropDownList; i++ ) {n");
buf.append(" if (dropDownLists[i].name == '").append(controlName).append("')n");
buf.append(" dropDownList = dropDownLists[i];n");
buf.append(" }n");
buf.append(" if ( dropDownList ) {n");
buf.append(" dropDownList.setAttribute('maxSelected',").append(max).append(");n");
buf.append(" var options = dropDownList.options;n");
buf.append(" // init each option with its selected (keeper) statusn");
buf.append(" for ( var i = 0; i < options.length; i++ )n");
buf.append(" options[i].setAttribute('keeper', options[i].selected);n");
buf.append(" dropDownList.onchange = // assign onchange handler functionn");
buf.append(" function() {n");
buf.append(" var max = this.getAttribute('maxSelected');n");
buf.append(" var options = this.options;n");
buf.append(" var counter = 0;n");
buf.append(" // count the total selected, exit loop if max exceededn");
buf.append(" for ( var i = 0; i < options.length && counter <= max; i++ )n");
buf.append(" if (options[i].selected) counter++;n");
buf.append(" if ( counter > max ) { // too many, revert selectionn");
buf.append(" for ( var i = 0; i < options.length; i++ )n");
buf.append(" options[i].selected = (new String(options[i].getAttribute('keeper')) == 'true');n");
if (displayAlert) {
buf.append(" alert('").append(errorMessage).append("');n");
}
buf.append(" } else { // set 'keeper' status on the selected optionsn");
buf.append(" for ( var i = 0; i < options.length; i++ )n");
buf.append(" options[i].setAttribute('keeper', options[i].selected);n");
buf.append(" }n");
buf.append(" }n");
buf.append(" }n");
buf.append("</script>n");
out.write(buf.toString());
}
}
Conclusion
Validation ensures that your controls are delivered good data.
Validation allows users to fix malformed data, and client-side
validation alerts users immediately, before bad data is
submitted to the server.
The custom validator in this article takes advantage of the
WDK 5 validation framework’s base classes to build a simple
reusable validator, complete with client-side validation, in
only a few hours.