Sonntag, 17. Oktober 2010

A Customized Validation Feedback Container for Wicket Form Components

Introduction

Wicket provides a set of mechanisms for validating entered data and displaying error messages caused by malformed user input. There are the following two feedback components (see Wicket 1.4.9) which help to show any validation errors.
The existing feedback component FormComponentFeedbackBorder org.apache.wicket.markup.html.form.validation.FormComponentFeedbackBorder helps to mark components that caused a validation error. It wraps another form component, e.g., a text field. In the case a text field causes a validation error, an asterisk (*) trailing the component indicates the validation error is shown, whereas the corresponding error message may be shown in a feedback panel (org.apache.wicket.markup.html.panel.FeedbackPanel), somewhere else on the same page. This article presents an improved feedback mechanism for validation errors replacing the FormComponentFeedbackBorder component and allowing one to handle more than component that cause together a validation error. This is often the case when having a form-based validation (see IFormValidator and Custom Form Validator). Furthermore, the presented component uses CSS classes to show validation errors.

The code for the Wicket component described in the following can be downloaded.

Motivation

Recently, I had to implement a system with a complex validation procedure for the entered data using Wicket. The customer had the following requirements:
  • The mandatory fields were denoted by an asterisk (*) which resulted in a confusion with the asterisk shown by a FormComponentFeedbackBorder component. The customer wanted rather to indicate a validation error occurred at a component using a different way than showing an asterisk, e.g., by showing components causing a validation error in a different background color.
  • Some of the validation steps included form-based validation. This means that several values together form a validation unit. The customer wanted that all fields involved in a form-based validation should visualize the validation error.
However, the requirements stated above could not be realized with the existing validation feedback components. Therefore, I was intensively looking for a Wicket component fulfilling these requirements. To the best of my knowledge, I did not find one that solved exactly this problem.

Extending the Feedback Mechanism

Consequently, I implemented a new Wicket component that solves the above issues and uses org.apache.wicket.markup.html.form.validation.FormComponentFeedbackBorder as a basis. The implementation provides a container which contains one or more form components that may cause validation errors. Any error is displayed by adding a CSS class visualizing the form element in the container that is responsible for showing the error. The default behavior is that if one or more component contained in the container causes a validation error, all components in the container display the error.

There are four properties that allow one to change this default behavior. The first two allow the user of the feedback component to define which set of components in the feedback container show a validation error:
  1. It is possible to define a set of components in the container which will show the errors occurring in the container. If this set is defined, any component that is not in this set will not show the error.
  2. There is a set of elements that explicitly define the components that will show an error, i.e., this is the opposite of 1. Note that either the first way of defining the visualizing components should be used or the second, but not both.
The second two properties allow the user of the feedback component to define which set of components in the feedback container is checked as source of a validation error:
  1. It is possible to define a set of components contained in the feedback container that will be ignored as a source of validation errors.
  2. As an opposite way, it is possible to define a set of components that is are observed as a source of validation errors. Note that either the first way of defining the components that are a source of validation errors should be used or the second way, but not both.
The components of the sets described above are referred to by their Wicket ids.

Example

The following example is based on a form that queries a user for his/her name and account information. There may be two different types of accounts: first, postal accounts which just ask for an account number and an account holder, and second, bank accounts which ask also for the address of the bank. The following Figure 1 shows a screen shot of the corresponding web form.

Figure 1: A sample application showing a simple web form for entering bank or postal account information.

The application should provide a validation mechanism which checks the following:
  1. Either the bank account radio button or the postal account radio button must be selected.
  2. If the bank account is checked, the corresponding fields (account number, address of bank, account holder) are mandatory.
  3. If the postal account is ticked, the corresponding fields (account number, account holder) are mandatory.
If one of these validation errors occur, the involved fields must be emphasized. With the conventional FormComponentFeedbackBorder container provided by the Wicket framework, this behavior showing the error feedback is not possible because the feedback border can just be applied to exactly one component.

The presented validation feedback container solves the problem. It provides a possibility to nest feedback containers and to use a CSS class to mark all or just a part of the components that caused the validation feedback errors. Figure 2 shows how the provided account information is nested by using this new component.

Figure 2: The Web GUI showing the nested validation feedback containers.

The outer feedback container is responsible for showing any validation errors occurring for the radio button group containing the choice “Bank Account” and “Postal Account”. It is visualized in the figure by the red box with the number 1. Apart from this feedback container there are five feedback containers for any validation errors occurring in the text fields designated by the red boxes with the numbers 2, 3, 4, 5, and 6.

In the case neither “Bank Account” nor “Postal Account” is chosen and submit is pressed, both labels will be marked with a validation error (see Fig. 3).

In the case “Bank Account” is checked, the fields 2, 3, and 4 are enabled and checked for the correctness when submitting the data. In the case one of these fields cause a validation error when pressing submit, the corresponding fields are marked (Fig. 4).

The equivalent validation feedback behavior is given for “Postal Account” and the corresponding fields (Fig. 5).

Figure 3: Showing a validation error for the outer validation feedback container.

Figure 4: Showing validation errors for the bank detail fields.

Figure 5: Showing validation errors for the postal detail fields.

Implementing the Example Above

The presented validation feedback container is implemented by the class com.blogspot.m3g4h4rd.wicket.CSSComponentFeedbackContainer and can be found in the archive file (.zip) provided by the link at the end of this article.

The following Wicket-HTML and Java source of the above Web-UI shows how the feedback container is used.

<html>
<body>
<wicket:panel>
<!-- Container showing validation errors -->
<wicket:container wicket:id="accountsFeedbackContainer">
<!-- Container for the account radio group -->
<wicket:container wicket:id="accountRadioGroup">
<br/>
<b>
<span wicket:id="accountInformationLabel">
Account Information
</span>
</b>
<table border="0">
<tr>
<td><input type="radio" wicket:id="bankAccount">
<span wicket:id="bankAccountLabel">Bank Account</span>
</td>
<td>
<table border="0">
<tr>
<td>
<span wicket:id="bankAccountNumberLabel">
Bank Account Number:
</span>
</td>
<td>
<wicket:container wicket:id="bankAccountNumberFeedback">
<input wicket:id="bankAccountNumber"/>
</wicket:container>
</td>
</tr>
<tr>
<td>
<span wicket:id="bankAddressLabel">
Address of Bank:
</span>
</td>
<td>
<wicket:container wicket:id="bankAddressFeedback">
<input wicket:id="bankAddress"/>
</wicket:container>
</td>
</tr>
<tr>
<td>
<span wicket:id="bankAccountHolderLabel">
Bank AccountHolder:
</span>
</td>
<td>
<wicket:container wicket:id="bankAccountHolderFeedback">
<input wicket:id="bankAccountHolder"/>
</wicket:container>
</td>
</tr>
</table>
</td>
</tr>
<tr><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr>
<td>
<input type="radio" wicket:id="postalAccount">
<span wicket:id="postalAccountLabel">
Postal Account
</span>
</td>
<td>
<table border="0">
<tr>
<td>
<span wicket:id="postalAccountNumberLabel">
Postal Account Number:
</span>
</td>
<td>
<wicket:container wicket:id="postalAccountNumberFeedback">
<input wicket:id="postalAccountNumber"/>
</wicket:container>
</td>
</tr>
<tr>
<td>
<span wicket:id="postalAccountHolderLabel">
Postal Account Holder:
</span>
</td>
<td>
<wicket:container wicket:id="postalAccountHolderFeedback">
<input wicket:id="postalAccountHolder"/>
</wicket:container>
</td>
</tr>
</table>
</td>
</tr>
</table>
</wicket:container>
</wicket:container>
</wicket:panel>
</body>
</html>
The above Wicket-HTML code contains several >wicket:container< tags that are used to bind the feedback container. The outer container (1) is referred as accountsFeedbackContainer, whereas bankAccountNumberFeedback, bankAddressFeedback, bankAccountHolderFeedback, postalAccountNumberFeedback, and postalAccountHolderFeedback are the (inner) containers 2 – 6 in Fig. 2.

The CSS class which is used to visualize components that caused a validation errors is defined as

.errorFeedback { background-color: #FA8895; }

If this CSS class is referred to by an HTML element, it causes the element to be shown with a red background. This CSS class is used by the presented example for showing validation errors by the feedback container. The following code snippets show how. It creates the feedback container for the feedback panel (1) in Figure 2.

// initializes the feedback container
accountsFeedbackContainer = new CSSFeedbackContainer("accountsFeedbackContainer",
"errorFeedback");
this.add(accountsFeedbackContainer);

The first argument of the constructor CSSFeedbackContainer is the id of the markup container to which the feedback panel will be bound. The second argument is the name of the CSS class that is used to visualize a feedback error.

// Set the components that will show a validation error feedback
accountsFeedbackContainer.addErrorFeedbackComponetIds(
new String[]{"bankAccountLabel", "postalAccountLabel"});

The above code adds the ids of the two labels bankAccountLabel and postalAccountLabel as components that will show validation error feedback if any of the components that are observed as source of validation error return an error.

// Set the components whose validation errors will be ignored by this component
accountsFeedbackContainer.addIgnoredComponentIds(
new String[]{"bankAddress",
"bankAccountNumber",
"bankAccountHolder",
"postalAccountNumber",
"postalAccountHolder"});

The code above excludes any validations errors caused by the components with the id bankAddress, bankAccountNumber, bankAccountHolder, postalAccountNumber, and postalAccountHolder. This is necessary, as those components are each handled by an own feedback container that is, in turn, contained in the outer feedback container.

accountsFeedbackContainer.add(accountRadioGroup);

The above code adds the radio group, which contains the radio button for the selection of either a bank or a postal account, to the feedback container. All elements of the bank account and postal account will be in turn added directly or indirectly added to the accountRadioGroup container or one of its sub-container, respectively.

The input fields of the bank account and postal account are enclosed by an own feedback container handling all validation errors that occur on their own. The following code describes how the inner feedback container for the bank account number is created.
// bank account number text field and label
bankAccountNumberLabel = new Label("bankAccountNumberLabel",
new Model("Account Number:"));
bankAccountNumber = new TextField("bankAccountNumber");

// feedback for validation errors of the bank account number
CSSFeedbackContainer bankAccountNumberFeedback =
new CSSFeedbackContainer("bankAccountNumberFeedback",
"errorFeedback");

accountRadioGroup.add(bankAccountNumberFeedback);

bankAccountNumberFeedback.add(bankAccountNumber);
bankAccountNumber.setRequired(true);
accountRadioGroup.add(bankAccountNumberLabel);

The above code simply binds the bank account number label and the corresponding bank account number text field to the corresponding elements in the Wicket-HTML. Thereafter, a new feedback container (bankAccountNumberFeedback) is created which is then added to the accountRadioGroup. The account number label and the account number text field are added to the feedback container. The code of the other parts in the Wicket UI are similar to the above code.

Hands-On
If you like to test and see in detail how it works, download the source code for the above example, including the feedback component, from here. Unzip it. Then run it with Maven 2 by entering
mvn clean jetty:run

After startup, the demo web application is reachable under

http://localhost/WicketCSSFeedback/

Conclusions
This article presented a feedback container component which allows one to
  • show validation feedback for multiple components involved in an error of a form-validation.
  • use a CSS class to show the feedback of a validation error.

3 Kommentare:

  1. Hi, thanks for this great article. I try to download the source code but I have the following error : Forbidden Error 403.

    AntwortenLöschen
  2. Hi, I had no problem to download the file with the link:

    https://docs.google.com/leaf?id=0B_HLXD4_Sf3pMDNkNjlkZmEtZjk5Ni00ODRmLWFjNTItNThjZDc0MWI2NmZl&hl=en

    Could you please try that again?

    AntwortenLöschen
  3. Nice blog, very interesting to read
    I have bookmarked this article page as i received good information from this.

    Best ERP Software in Hyderabad

    ERP Hyderabad

    ERP Software Providers in Hyderabad

    AntwortenLöschen