A Form in Wicket is a component that takes user input and processes it upon submission. This component is a logical holder of one or more input fields that get processed together. The Form component, like all others, must be bound to an HTML equivalent, in this case the <form> tag.
<form wicket:id=”form”>
Name: <input type=”text” wicket:id=”name” />
<input type=”submit” value=”Send” />
</form>
...
Form form = new Form(“form”) {
@Override
protected void onSubmit() {
System.out.println(“form submit”);
}
};
add(form);
form.add(new TextField(“name”, new Model(“”));
Form input controls can each have their own Models attached to them, or can inherit from their parent, the Form. This is usually a good place to use CompoundPropertyModel as it gets rid of a lot of duplicate code. As you can see, each input component should be added to the Form element.
Wicket uses a POST to submit your form, which can be changed by overriding the Form’s getMethod and returning Form.METHOD_GET. Wicket also uses a redirect to buffer implementation details of form posts which gets around the form repost popup. The following behavior settings can be changed:
Name |
Setting |
Description |
No redirect |
IRequestCycleSettings.ONE_PASS_RENDER |
Renders the response directly |
Redirect to buffer |
IRequestCycleSettings.REDIRECT_BUFFER |
Renders the response directly to a buffer, redirects the browser and prevents reposting the form |
Redirect to render |
IRequestCycleSettings. REDIRECT_TO_RENDER |
Redirects the browser directly; renders in a separate request |
Components of a Form
The following table lists all the different form components available, and how to use them with Models.
Name |
Example |
TextField |
<input type=”text” wicket:id=”firstName” />
...
add(new TextField(“firstName”, new
PropertyModel(person, “firstName”));
|
TextArea |
<textarea wicket:id=”comment”></textarea>
...
add(new TextArea(“comment”, new
PropertyModel(feedback, “comment”));
|
Button |
<form wicket:id=”form”>
<input type=”submit” value=”Submit”
wicket:id=”submit” />
</form>
...
Form form = new Form(“form”) {
@Override
protected void onSubmit() {
System.out.println(“onSubmit called”);
}
};
add(form);
form.add(new Button(“submit”));
|
CheckBoxMultipleChoice |
<span wicket:id=”operatingSystems”>
<input type=”checkbox” /> Windows <input type=”checkbox” /> OS/2 Warp</span>
...
add(new CheckBoxMultipleChoice(“operat
ingSystems”, new PropertyModel(system,
“operatingSystems”), Arrays.asList(“Windows”,
“OS X”, “Linux”, “Solaris”, “HP/UX”,
“DOS”)));
|
DropDownChoice |
<select wicket:id=”states”>
<option>[state]</option>
</select>
...
add(new DropDownChoice(“states”, new
PropertyModel(address, “state”),
listOfStates));
|
PasswordTextField |
<input type=”password” wicket:id=”password”
/>
...
add(new PasswordTextField(“password”, new
PropertyModel(user, “password”));
|
RadioChoice |
<span wicket:id=”gender”>
<input type=”radio” /> Male<br />
<input type=”radio” /> Female</br />
</span>
...
add(new RadioChoice(“sex”, new
PropertyModel(person, “gender”), Arrays.
asList(“Male”, “Female”));
|
SubmitLink |
<form wicket:id=”form”>
<a href=”#”
wicket:id=”submitLink”>Submit</a>
</form>
...
form.add(new SubmitLink(“submitLink”) {
@Override
public void onSubmit() {
System.out.println(“submitLink
called”);
}
});</td>
</tr>
|
Validation
When dealing with user input, we need to validate it against what we’re expecting, and guide the user in the right direction if they stray. Any user input is processed through this flow:
- Check that the required input is supplied
- Convert input values from String to the expected type
- Validate input using registered validators
- Push converted and validated input to models
- Call onSubmit or onError depending on the result
Wicket provides the following set of validators:
Resource Key |
Example |
Required |
textField.setRequired(true) |
RangeValidator.range |
numField.add(RangeValidator.range(0,10)) |
MinimumValidator.minimum |
numField.add(MinimumValidator.minimum(0)) |
MaximumValidator.maximum |
numField.add(MaximumValidator.maximum(0)) |
StringValidator.exact |
textField.add(StringValidator.exact(8)) |
StringValidator.range |
textField.add(StringValidator.range(6,18)) |
StringValidator.maximum |
textField.add(StringValidator.maximum(8)) |
StringValidator.minimum |
textField.add(StringValidator.minimum(2)) |
DateValidator.range |
dateField.add(DateValidator.range(startDate, endDate)) |
DateValidator.minimum |
dateField.add(DateValidator.minimum(minDate)) |
DateValidator.maximum |
dateField.add(DateValidator.maximum(maxDate)) |
CreditCardValidator |
ccField.add(new CreditCardValidator()) |
PatternValidator |
textFIeld.add(new PatternValidator(“\d+”) |
EmailAddressValidator |
emailField.add(EmailAddressValidator.getInstance()) |
UrlValidator |
urlField.add(new UrlValidator()) |
EqualInputValidator |
add(new EqualInputValidator(formComp1,formComp2)) |
EqualPasswordInputValidator |
Add(new EqualPasswordInputValidator(passFld1, passFld2)) |
More than one validator can be added to a component if needed. For instance, if you have a password that needs to be within the range of 6 – 20 characters, must be alphanumeric and is required, simply chain the needed validators above to your component. If the validators listed above don’t fit your needs, Wicket lets you create your own and apply them to your components.
public class PostalCodeValidator extends AbstractValidator {
public PostalCodeValidator() {
}
@Override
protected void onValidate(IValidatable validatable) {
String value = (String)validatable.getValue();
if(!postalCodeService.isValid(value)) {
error(validatable);
}
}
@Override
protected String resourceKey() {
return “PostalCodeValidator”;
}
@Override
protected Map variablesMap(IValidatable validatable) {
Map map = super.variablesMap(validatable);
map.put(“postalCode”, n);
return map;
}
}
When Wicket has completed processing all input it will either pass control to the Form’s onSubmit, or the Form’s onError..If you don’t choose to override onError, you’ll need a way to customize the error messages that show up.
Feedback Messages
Apache Wicket offers a facility to send back messages for failed validations or flash messages to provide notification of status after submitting a form or performing some action. Wicket’s validators come with a default set of feedback messages in a variety of languages, which you can override in your own properties files. Here’s the order Wicket uses to grab messages out of resource bundles:
Location |
Order |
Description |
Example |
Page class |
1 |
Messages Specific to a page |
Index.properties Index_es.properties |
Component class |
2 |
Messages specific to a component |
AddressPanel_es.properties CheckOutForm.properties |
Custom Application class |
3 |
Default application-wide message bundle |
RefcardApplication_es_
MX.properties
RefcardApplication_
es.properties
RefcardApplication.
properties
|
During a Form submission, if you’d like to pass back messages to the end user, Wicket has a message queue that you can access with any component:
info(“Info message”);
warn(“Warn message”);
error(“Error message”);
With that added to the queue, the most basic method of showing these to users is to use the FeedbackPanel component which you can add to your Page as follows:
<div wicket:id=”feedback”></div>
…
add(new FeedbackPanel(“feedback”));
When you’d like to get them back out again, it will give you an Iterator to cycle through on the subsequent page:
getSession().getFeedbackMessages().iterator();
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}