The author treats Struts UI tags for form controls as a poor subset of HTML tags, particularly lacking FORM and DATA-* attributes. This article describes how to use form input HTML tags with this library.
An important note is whereas standard Struts design uses the same Action for form processing and display, this
library separates these into different Actions. To display a form field values, the OGNL expression is the form
name and the property name, such as <s:property value="searchForm.id" />. The form input tag
just uses the receiving form field name, such as <INPUT NAME="id">
Also, JSP code access formatted string, form field values, not any converted, non-string value.
The form field value is easily substituted, such as below.
<INPUT CLASS="field" STYLE="width: 200px;" NAME="name" TYPE="TEXT" VALUE="<s:property value="form.name" />" > <TEXTAREA CLASS="field" STYLE="height: 300px; width: 820px;" NAME="message"><s:property value="form.message" /></TEXTAREA>
The CHECKED attribute must be written when appropriate. Checkboxes are for boolean fields and the formatted values are '1' and '', so it's easiest to check for empty string. Radio buttons are typically for enumerated type fields and the formatted values are the value name as a string. Thus, the ternary operator can result in 'CHECKED' or not, as shown below.
<INPUT CLASS="field" TYPE="CHECKBOX" NAME="enable" <s:property value="(form.enable != '')?'CHECKED':''" /> > <INPUT CLASS="field" TYPE="RADIO" NAME="rgb" VALUE="RED" <s:property value="(testForm.rgb == 'RED')?'CHECKED':''" /> > <INPUT CLASS="field" TYPE="RADIO" NAME="rgb" VALUE="GREEN" <s:property value="(testForm.rgb == 'GREEN')?'CHECKED':''" /> > <INPUT CLASS="field" TYPE="RADIO" NAME="rgb" VALUE="BLUE" <s:property value="(testForm.rgb == 'BLUE')?'CHECKED':''" /> >
The form field to receive the value of a drop-down list is typically a single integer or enumerated type but the viewer Action needs a view helper for construction of the full list. These are typically subclasses of the following Templates.
| Type | Template class | Notes |
|---|---|---|
| Enumerated type | EnumSingleSelectBoxDisplay2<E> | |
| Grouped enumerated type | GroupedEnumSingleSelectBoxDisplay<E> | Groups enumerated values using OPTGROUP. |
| Grouped record list | GroupedSingleSelectBoxDisplay<K,T,G> | Groups records using OPTGROUP. T is usually a database record, K its primary key, and G record or String. |
| Integer list | IntegerListSelectBoxDisplay2 | |
| Record list | SingleSelectBoxDisplay2<K,T> | T is usually a database record and K its primary key. |
The example below is a view helper for countries where the id is the form field value and the name is the display text.
public class CountrySelectBoxDisplay extends SingleSelectBoxDisplay2<Integer,CountryVO> {
{@code @Override}
protected Integer getKey(CountryVO item) {
return item.getId();
}
{@code @Override}
protected String getText(CountryVO item) {
return item.getName();
}
{@code @Override}
protected String getValue(Integer key) {
return Integer.toString(key);
}
{@code @Override}
protected boolean hasBlankValue() {
return true;
}
}
Below is the relevant lines from the viewer Action.
{@code @Form}
private AddVatRateForm form;
private CountrySelectBoxDisplay operatorCountrySelectBoxDisplay;
...
operatorCountrySelectBoxDisplay = new CountrySelectBoxDisplay();
operatorCountrySelectBoxDisplay.setModel(getCountries());
operatorCountrySelectBoxDisplay.setSelectedValue(form.getOperatorCountryId());
Below creates the HTML tags for the drop-down list.
<SELECT CLASS="field" STYLE="width: 140px;" NAME="operatorCountryId">
<s:iterator var="operatorCountry" value="operatorCountrySelectBoxDisplay.list" status="loop">
<OPTION <s:property value='#operatorCountry.selectedAttribute' /> VALUE="<s:property value='#operatorCountry.value' />"
><s:property value='#operatorCountry.text' /></OPTION>
</s:iterator>
</SELECT>
Longer drop-down lists split into groups are also supported. For example, below, services may refer to their named group, groups have a display order, and services have a display order within their group.
public class ServiceSelectBoxDisplay extends GroupedSingleSelectBoxDisplay<Integer,ServiceDTO,ServiceGroupDTO> {
protected String getBlankText() {
return "-- please select --";
}
{@code @Override}
protected String getValue(ServiceDTO item) {
return Integer.toString(item.getId());
}
{@code @Override}
protected String getText(ServiceDTO item) {
return item.getName();
}
{@code @Override}
protected ServiceGroupDTO getGroup(ServiceDTO item) {
return item.getServiceGroup();
}
{@code @Override}
protected String getGroupLabel(ServiceGroupDTO group) {
return (group != null)?group.getName():"(Ungrouped)";
}
{@code @Override}
public Integer getKey(ServiceDTO item) {
return item.getId();
}
protected Comparator<SelectBoxGroupDisplay<Integer,ServiceDTO,ServiceGroupDTO>> getGroupSortComparator() {
return (o1,o2) -> ((o1.getData() != null)?o1.getData().getDisplayOrder():0) - ((o2.getData() != null)?o2.getData().getDisplayOrder():0);
}
protected Comparator<SelectBoxItemDisplay2<Integer,ServiceDTO>> getSortComparator() {
return (o1,o2) -> (o1.getData().getDisplayOrder() - o2.getData().getDisplayOrder());
}
}
The HTML tags are created by looping through each group, then each member within.
<SELECT SIZE="1" NAME="serviceId">
<s:iterator value="serviceSelectBoxDisplay.list" var="serviceGroupDisplay">
<OPTGROUP LABEL="<s:property value="#serviceGroupDisplay.text"/>">
<s:iterator value="#serviceGroupDisplay.children" var="serviceDisplay">
<OPTION VALUE="<s:property value="#serviceDisplay.value"/>" <s:property value="#serviceDisplay.selectedAttribute"/>
><s:property value="#serviceDisplay.text"/></OPTION>
</s:iterator>
</OPTGROUP>
</s:iterator>
</SELECT>
SELECT HTML tags using MULTIPLE generate multiple parameters of the same name. Unlike standard Struts, multiple parameters with the same name aren't converted to other data types but a String array on a form will be set. The formatted values can then be manually converted, such as below.
private String[] serviceIds;
private Collection<Integer> parsedServiceIds;
...
public void doValidate2(ValidationAware2 validationAware, TextProvider textProvider) {
parsedOtherServiceIds = new ArrayList<>();
for (String serviceId: serviceIds) {
parsedServiceIds.add(Integer.parseInt(serviceId));
}
}
Like the single drop-down list, create a view helper from the MultiSelectBoxDisplay<K,T> Template class.
public class ServiceMultiSelectBoxDisplay extends MultiSelectBoxDisplay<Integer,ServiceDTO> {
{@code @Override}
protected Integer getKey(ServiceDTO item) {
return item.getId();
}
{@code @Override}
protected String getText(ServiceDTO item) {
return item.getName();
}
{@code @Override}
protected String getValue(ServiceDTO item) {
return Integer.toString(item.getId());
}
}
Below is the relevant lines from the viewer Action.
serviceMultiSelectBoxDisplay = new ServiceMultiSelectBoxDisplay();
serviceMultiSelectBoxDisplay.setModel(getServices());
serviceMultiSelectBoxDisplay.setSelectedValues(form.getParsedServiceIds());