Modified: websites/production/tapestry/content/using-select-with-a-list.html
==============================================================================
--- websites/production/tapestry/content/using-select-with-a-list.html
(original)
+++ websites/production/tapestry/content/using-select-with-a-list.html Tue Aug
16 18:12:09 2022
@@ -142,37 +142,14 @@
<!-- /// Content Start -->
<div id="content">
- <div id="ConfluenceContent"><p>
-</p><div class="atb-scrollbar-macro">
- <div class="prev">
- <a href="meta-programming-page-content.html" rel="prev">
- <span class="aui-icon aui-icon-small
atb-icon-arrow-left">Previous</span>
- <span class="title">Meta-Programming Page
Content</span>
- </a>
-
- </div>
- <div class="parent">
- <a href="cookbook.html" rel="parent">
- <span class="aui-icon
aui-icon-small atb-icon-arrow-up">Up</span>
- <span class="title">Cookbook</span>
- </a>
-
- </div>
- <div class="next">
- <a href="ioc-cookbook.html" rel="next">
- <span class="title">IoC cookbook</span>
- <span class="aui-icon aui-icon-small
atb-icon-arrow-right">Next</span>
- </a>
-
- </div>
-</div><h1 id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a
List</h1><p>The documentation for the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select
Component</a> and the <a href="tapestry-tutorial.html">Tapestry Tutorial</a>
provide simplistic examples of populating a drop-down menu (as the (X)HTML
<em>Select</em> element) using comma-delimited strings and enums. However, most
real-world Tapestry applications need to populate such menus using values from
a database, commonly in the form of java.util.List objects. Doing so generally
requires a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a>
and a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
bound to the Select component with its "model" and "encoder"
parameters:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+ <div id="ConfluenceContent"><p></p><p></p><h1
id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a
List</h1><p>The documentation for the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select
Component</a> and the <a href="tapestry-tutorial.html">Tapestry Tutorial</a>
provide simplistic examples of populating a drop-down menu (as the (X)HTML
<em>Select</em> element) using comma-delimited strings and enums. However, most
real-world Tapestry applications need to populate such menus using values from
a database, commonly in the form of java.util.List objects. Doing so generally
requires a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a>
and a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
bound to the Sele
ct component with its "model" and "encoder" parameters:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre><code class="language-java"><t:select t:id="colorMenu"
value="selectedColor" model="ColorSelectModel" encoder="colorEncoder" />
</code></pre>
</div></div><p>In the above example, ColorSelectModel must be of type
SelectModel, or anything that Tapestry knows how to <a
href="parameter-type-coercion.html">coerce</a> into a SelectModel, such as a
List or a Map or a "value=label,value=label,..." delimited string, or anything
Tapestry knows how to coerce into a List or Map, such as an Array or a
comma-delimited String.</p><h2
id="UsingSelectWithaList-SelectModel">SelectModel</h2><p></p><div
class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
<p> <strong>JumpStart Demos:</strong>
<span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/totalcontrolobject"
rel="nofollow">Total Control Object Select<sup><img align="middle"
class="rendericon" src="/images/confluence/icons/linkext7.gif" height="7"
width="7" alt="" border="0"></sup></a></span>
<span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/id"
rel="nofollow">ID Select<sup><img align="middle" class="rendericon"
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt=""
border="0"></sup></a></span>
- <span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyid"
rel="nofollow">Easy ID Select<sup><img align="middle" class="rendericon"
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt=""
border="0"></sup></a></span></p></div>A SelectModel is a collection of options
(specifically <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html">OptionModel</a>
objects) for a drop-down menu. Basically, each option is a value (an object)
and a label (presented to the user).<p></p><p>If you provide a property of type
List for the "model" parameter, Tapestry automatically builds a SelectModel
that uses each object's toString() for both the select option value and the
select option label. For database-derrived lists this is rarely useful,
however, since after form submission you would then have to look up the
selected object using that label.</p><p>If you provide a M
ap, Tapestry builds a SelectModel that uses each item's key as the encoded
value and its value as the user-visible label. This is more useful, but if you
are going to build a copy of the list as a map just for this purpose, you may
as well let Tapestry do it for you, using SelectModelFactory.</p><h2
id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have
Tapestry create a SelectModel for you, use the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html">SelectModelFactory</a>
service. SelectModelFactory creates a SelectModel from a List of objects (of
whatever type) and a label property name that you choose:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page
class)</b></div><div class="codeContent panelContent pdl">
+ <span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyid"
rel="nofollow">Easy ID Select<sup><img align="middle" class="rendericon"
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt=""
border="0"></sup></a></span></p></div><p>A SelectModel is a collection of
options (specifically <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html">OptionModel</a>
objects) for a drop-down menu. Basically, each option is a value (an object)
and a label (presented to the user).</p><p></p><p>If you provide a property of
type List for the "model" parameter, Tapestry automatically builds a
SelectModel that uses each object's toString() for both the select option value
and the select option label. For database-derrived lists this is rarely useful,
however, since after form submission you would then have to look up the
selected object using that label.</p><p>If you prov
ide a Map, Tapestry builds a SelectModel that uses each item's key as the
encoded value and its value as the user-visible label. This is more useful, but
if you are going to build a copy of the list as a map just for this purpose,
you may as well let Tapestry do it for you, using SelectModelFactory.</p><h2
id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have
Tapestry create a SelectModel for you, use the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html">SelectModelFactory</a>
service. SelectModelFactory creates a SelectModel from a List of objects (of
whatever type) and a label property name that you choose:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page
class)</b></div><div class="codeContent panelContent pdl">
<pre><code class="language-java">@Property
private SelectModel colorSelectModel;
@Inject
@@ -195,7 +172,7 @@ public String toString() {
</code></pre>
</div></div><p>But that is contorting the purpose of the toString() method,
and if you go to that much trouble you're already half way to the recommended
practice: creating a ValueEncoder.</p><h2
id="UsingSelectWithaList-ValueEncoder">ValueEncoder</h2><p>In addition to a
SelectModel, your Select menu is likely to need a ValueEncoder. While a
SelectModel is concerned only with how to construct a Select menu, a
ValueEncoder is used when constructing the Select menu <em>and</em> when
interpreting the encoded value that is submitted back to the server. A
ValueEncoder is a converter between the type of objects you want to represent
as options in the menu and the client-side encoded values that uniquely
identify them, and vice-versa.</p><div class="navmenu" style="float:right;
background:#eee; margin:3px; padding:0 1em">
<p> <strong>JumpStart Demo:</strong>
- <span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyobject"
rel="nofollow">Easy Object Select<sup><img align="middle" class="rendericon"
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt=""
border="0"></sup></a></span></p></div>Most commonly, your ValueEncoder's
toClient() method will return a unique ID (e.g. a database primary key, or
perhaps a UUID) of the given object, and its toValue() method will return the
<em>object</em> matching the given ID by doing a database lookup (ideally using
a service or DAO method).<p></p><p>If you're using one of the ORM integration
modules (<a href="hibernate.html">Tapestry-Hibernate</a>, <a
href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a class="external-link"
href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder"
rel="nofollow">Tapestry-Cayenne</a>), the ValueEncoder is automatically
provided for each of your mapped entity classes. The Hibernat
e module's implementation is typical: the primary key field of the object
(converted to a String) is used as the client-side value, and that same primary
key is used to look up the selected object.</p><p>That's exactly what you
should do in your own ValueEncoders too:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your
com.example.myappname.encoders package)</b></div><div class="codeContent
panelContent pdl">
+ <span class="nobr"><a class="external-link"
href="https://tapestry-jumpstart.org/jumpstart/examples/select/easyobject"
rel="nofollow">Easy Object Select<sup><img align="middle" class="rendericon"
src="/images/confluence/icons/linkext7.gif" height="7" width="7" alt=""
border="0"></sup></a></span></p></div><p>Most commonly, your ValueEncoder's
toClient() method will return a unique ID (e.g. a database primary key, or
perhaps a UUID) of the given object, and its toValue() method will return the
<em>object</em> matching the given ID by doing a database lookup (ideally using
a service or DAO method).</p><p></p><p>If you're using one of the ORM
integration modules (<a href="hibernate.html">Tapestry-Hibernate</a>, <a
href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a class="external-link"
href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder"
rel="nofollow">Tapestry-Cayenne</a>), the ValueEncoder is automatically
provided for each of your mapped entity classes. The H
ibernate module's implementation is typical: the primary key field of the
object (converted to a String) is used as the client-side value, and that same
primary key is used to look up the selected object.</p><p>That's exactly what
you should do in your own ValueEncoders too:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your
com.example.myappname.encoders package)</b></div><div class="codeContent
panelContent pdl">
<pre><code class="language-java">public class ColorEncoder implements
ValueEncoder<Color>, ValueEncoderFactory<Color> {
@Inject