blob: e10f2e754a9fdc09478c82399e20ed5d1b1e2a49 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2007 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document>
<properties>
<title>PropertySelection</title>
</properties>
<body>
<section name="PropertySelection">
<p>
Creates form elements that allow a property of an object to be set from a drop-down
list.
</p>
<p>
Uses a
<a href="../../apidocs/org/apache/tapestry/form/IPropertySelectionModel.html">IPropertySelectionModel</a>
to map between Java values that will be assigned, and textual labels that will
appear in the HTML response.
</p>
<p>
A useful property selection model is available (
<a href="../../apidocs/org/apache/tapestry/form/StringPropertySelectionModel.html">StringPropertySelectionModel</a>
, or
<a href="../../apidocs/org/apache/tapestry/form/BeanPropertySelectionModel.html">BeanPropertySelectionModel</a>).
You can also create your own model, as illustrated in the examples below.
</p>
<p>
Note that complex value Objects need to properly implement the <code>Object.equals()</code>
method if the correct initial item is to be displayed.
</p>
<p>
Informal parameters are applied to the <code>&lt;select&gt;</code> tag. To have greater control
over the <code>&lt;option&gt;</code> tags, you must use the <a href="select.html">Select</a> and
<a href="option.html">Option</a> components.
</p>
<p>
<strong>
See also:
<a href="../../apidocs/org/apache/tapestry/form/PropertySelection.html">org.apache.tapestry.form.PropertySelection</a>
,
<a href="select.html">Select</a>
,
<a href="option.html">Option</a>
,
<a href="radio.html">Radio</a>
,
<a href="radiogroup.html">RadioGroup</a>
,
<a href="form.html">Form</a>
,
<a href="../general/script.html">Script</a>
</strong>
</p>
<section name="Parameters">
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>Required</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td>value</td>
<td>Object</td>
<td>yes</td>
<td> </td>
<td>
The property to set. During rendering, this property is read, and sets
the default value of the selection (if it is null, no element is
selected). When the form is submitted, this property is updated based on
the new selection.
</td>
</tr>
<tr>
<td>model</td>
<td>
<a href="../../apidocs/org/apache/tapestry/form/IPropertySelectionModel.html">
IPropertySelectionModel
</a>
</td>
<td>yes</td>
<td> </td>
<td>
The model provides a list of possible labels, and matches those labels
against possible values that can be assigned back to the property.
</td>
</tr>
<tr>
<td>optionRenderer</td>
<td>
<a href="../../apidocs/org/apache/tapestry/form/IOptionRenderer.html">
IOptionRenderer
</a>
</td>
<td>yes</td>
<td>
<a href="../../apidocs/org/apache/tapestry/form/DefaultOptionRenderer.html">
DefaultOptionRenderer
</a>
</td>
<td>
Object used to render the <code>&lt;option&gt;Label&lt;/option&gt;</code> elements
within the enclosing <code>&lt;select&gt;</code> tags. The default implementation currently
handles only writing out the <code>disabled/selected</code> attributes corresponding the methods
implemented by
<a href="../../apidocs/org/apache/tapestry/form/IPropertySelectionModel.html">
IPropertySelectionModel
</a>.
<br /><br />
It is possible to implement more advanced display semantics of your options list by implementing a custom
<a href="../../apidocs/org/apache/tapestry/form/IOptionRenderer.html">
IOptionRenderer
</a> of your own. Things like <code>optgroup</code> and various indentation strategies are typically good
candidates for implementing custom renderers.
</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>no</td>
<td>false</td>
<td>
Controls whether the <code>&lt;select&gt;</code> is active or not. A disabled
PropertySelection does not update its value parameter. Corresponds to
the "disabled" HTML attribute.
</td>
</tr>
<tr>
<td>displayName</td>
<td>String</td>
<td>no</td>
<td> </td>
<td>
The user-presentable name for the component, which will be used by a
<a href="fieldlabel">FieldLabel</a>
connected to the component.
</td>
</tr>
<tr>
<td>validators</td>
<td>
Array or collection of
<a href="../../apidocs/org/apache/tapestry/form/validator/Validator.html">
Validator
</a>
</td>
<td>no</td>
<td> </td>
<td>
The validators to apply to the component. Something along the lines of:
<code>validators:required</code> .<br/><br/>
<strong>See also:</strong> <a href="../../usersguide/validation.html">Validation</a>
</td>
</tr>
</table>
<p>
Body:
<strong>removed</strong>
</p>
<p>
Informal parameters:
<strong>allowed</strong>
</p>
<p>
Reserved parameters:
<em>name</em>
</p>
</section>
<section name="Examples">
<subsection name="Example 1">
<p>
The PropertySelection component provides Gender selection drop down list
using a
<a href="../../apidocs/org/apache/tapestry/form/StringPropertySelectionModel.html">
StringPropertySelectionModel
</a>
</p>
<source xml:space="preserve"><![CDATA[
<form jwcid="@Form" listener="listener:formSubmit">
Gender: <select jwcid="@PropertySelection" model="ognl:@com.myexample.DetailsPage@GENDER_MODEL" value="ognl:gender"></select>
<input type="submit"/>
</form>
]]></source>
<source xml:space="preserve">
public abstract class DetailsPage extends BasePage {
public static final IPropertySelectionModel GENDER_MODEL =
new StringPropertySelectionModel(new String[] { "Unspecified", "Female", "Male" });
public abstract String getGender();
public void formSubmit(IRequestCycle cycle) {
// Process form submission
String genderSelection = getGender();
...
}
}
</source>
</subsection>
<subsection name="Example 2 : Custom IOptionRenderer">
<p>
The <code>optionRenderer</code> parameter allows you complete control over the display of your options list with custom
renderer implementations. The following example shows a sample custom renderer implementation for generating a google style
drop down actions list. <em>(similar to the gmail drop down actions list)</em>
</p>
<p>
The resulting option list would look something like:
</p>
<select name="sampleOptions">
<option value="-1" style="color: rgb(119, 119, 119);">choose..</option>
<option value="0" style="padding-left:1em;">Dogs</option>
<option value="1" style="padding-left:1em;">Elephants</option>
<option value="2" style="padding-left:1em;">Mongoose</option>
<option value="3" style="padding-left:1em;">Angry Chipmunks</option>
</select>
<source xml:space="preserve"><![CDATA[
/**
* Implementation of {@link IOptionRenderer} that pretty prints options
* that aren't disabled with padded whitespace at the beginning.
*/
public class FormattedOptionRenderer implements IOptionRenderer {
// Provided for efficiency / convenience
public static final IOptionRenderer DEFAULT_INSTANCE = new FormattedOptionRenderer();
/**
* {@inheritDoc}
*/
public void renderOptions(IMarkupWriter writer, IRequestCycle cycle, IPropertySelectionModel model, Object selected) {
int count = model.getOptionCount();
for (int i = 0; i < count; i++)
{
Object option = model.getOption(i);
writer.begin("option");
writer.attribute("value", model.getValue(i));
if (isEqual(option, selected, model))
writer.attribute("selected", "selected");
if (model.isDisabled(i))
writer.attribute("style", "color: rgb(119, 119, 119);");
if (i > 0)
writer.printRaw("&nbsp;");
writer.print(model.getLabel(i));
writer.end();
writer.println();
}
}
protected boolean isEqual(Object left, Object right, IPropertySelectionModel model) {
if (List.class.isInstance(right) && IPrimaryKeyConverter.class.isInstance(model))
{
List values = (List) right;
IPrimaryKeyConverter converter = (IPrimaryKeyConverter) model;
if (left == null)
return false;
for (Object option : values)
if (converter.getPrimaryKey(option).equals(converter.getPrimaryKey(left)))
return true;
return false;
}
// Both null, or same object, then are equal
if (left == right)
return true;
// If one is null, the other isn't, then not equal.
if (left == null || right == null)
return false;
// Both non-null; use standard comparison.
return left.equals(right);
}
}
]]></source>
</subsection>
<subsection name="Example 3">
<p>
Provides list of clothing items for the user to select. When the user
selects a cloting item from the list the description the label and price is
automatically updated. The list of clothing items would typically be loaded
from a database.
</p>
<p>PurchasePage.html</p>
<source xml:space="preserve"><![CDATA[
<body jwcid="@Body">
<form jwcid="@Form" listener="listener:formSubmit">
<label jwcid="@FieldLabel" field="component:itemSelection">Selection</label>
<select jwcid="itemSelection@PropertySelection"
model="ognl:itemSelectionModel"
value="ognl:clothingItem"
onchange="javascript:this.form.events.refresh();"
displayName="Choose an item"></select>
<input type="submit" value="Show me this item"/>
<span jwcid="@Conditional" condition="ognl:clothingItem!=null">
<p>Description: <span jwcid="@Insert" value="ognl:clothingItem.description"/></p>
<p>Label: <span jwcid="@Insert" value="ognl:clothingItem.label"/></p>
<p>Price: $<span jwcid="@Insert" value="ognl:clothingItem.price"/></p>
</span>
</form>
</body>
]]></source>
<p>PurchasePage.java</p>
<source xml:space="preserve">
public abstract class PurchasePage extends BasePage implements PageDetachListener {
private ItemSelectionModel model = null;
public abstract Item getClothingItem();
public abstract void setClothingItem(Item value);
public ItemSelectionModel getItemSelectionModel() {
if (model == null) {
List items = new ArrayList();
items.add(new Item(1, "Dress", "Cotton full length Summer dress", "CountryClub", "89.95"));
items.add(new Item(2, "Jacket", "Gorgeous jacket", "CountryClub", "119.95"));
model = new ItemSelectionModel(items);
}
return model;
}
public void formSubmit() {
// Process form submission
}
public void pageDetached(PageEvent pageEvent) {
model = null;
}
}
</source>
<p>Item.java</p>
<source xml:space="preserve">
public class Item implements Serializable {
private int id;
private String name;
private String description;
private String label;
private String price;
public Item(int id, String name, String desc, String label, String price) {
this.id = id;
this.name = name;
this.description = desc;
this.label = label;
this.price = price;
}
public int getId() { return id; }
public String getName() { return name; }
public String getDescription() { return description; }
public String getLabel() { return label; }
public String getPrice() { return price; }
}
</source>
<p>ItemSelectionModel.java</p>
<source xml:space="preserve">
public class ItemSelectionModel implements IPropertySelectionModel, Serializable {
private List itemList;
public ItemSelectionModel(List itemList) {
this.itemList = itemList;
}
public int getOptionCount() { return itemList.size(); }
public Object getOption(int index) {
return itemList.get(index);
}
public String getLabel(int index) {
return ((Item) itemList.get(index)).getName();
}
public String getValue(int index) { return Integer.toString(index); }
public Object translateValue(String value) {
return getOption(Integer.parseInt(value));
}
}
</source>
</subsection>
</section>
</section>
</body>
</document>