Author: bobharner
Date: Sun Sep 15 19:16:07 2013
New Revision: 878527
Log:
Manual updates to {code} section of doc pages as a temporary fix (until we can
cleanly incorporate Dan Kulp's fixes into our copy of SiteExporter)
Modified:
websites/production/tapestry/content/configuration.html
websites/production/tapestry/content/session-storage.html
websites/production/tapestry/content/switching-cases.html
websites/production/tapestry/content/tapestry-for-jsf-users.html
websites/production/tapestry/content/using-select-with-a-list.html
Modified: websites/production/tapestry/content/configuration.html
==============================================================================
--- websites/production/tapestry/content/configuration.html (original)
+++ websites/production/tapestry/content/configuration.html Sun Sep 15 19:16:07
2013
@@ -96,7 +96,7 @@
<p>Tapestry applications are configured almost entirely using Java, not XML.
However, a small but necessary amount of configuration occurs inside the
servlet deployment descriptor, WEB-INF/web.xml. Most of the configuration is
boilerplate, nearly the same for all applications.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
@@ -115,7 +115,7 @@
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
-]]></script>
+</pre>
</div></div>
<div class="navmenu" style="float:right; width:30%; background:#eee;
margin:3px; padding:3px"><p><font color="#539126"><b>Tapestry Requests vs.
Container Requests</b></font></p>
@@ -141,7 +141,7 @@
<p>Your application module class (usually AppModule.java) will typically
override some of Tapestry's default, or "factory", symbols, by contributing
overrides to the ApplicationDefaults service configuration. For example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>AppModule.java</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class AppModule
{
public static void
contributeApplicationDefaults(MappedConfiguration<String,String>
configuration)
@@ -150,7 +150,7 @@ public class AppModule
configuration.add(SymbolConstants.FILE_CHECK_INTERVAL, "10 m");
}
}
-]]></script>
+</pre>
</div></div>
<h2><a shape="rect"
name="Configuration-ConfigurationSymbolNames"></a>Configuration Symbol
Names</h2>
@@ -450,9 +450,9 @@ re-download them on subsequent pages).
<div style="border-right: 20px solid #D8E4F1;border-left: 20px solid
#D8E4F1;"><p> Some components, notably Grid, Pallete and Zone, have default
parameter values specified in terms of symbols. This means you can use these
symbols to modify the defaults for all instances of such components in your
application. For example, you can set the default rows per page for all Grid
instances by adding this to the <tt>contributeApplicationDefaults</tt> method
in your application's module class (typically AppModule.java):</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
configuration.add(ComponentParameterConstants.GRID_ROWS_PER_PAGE, "15");
-]]></script>
+</pre>
</div></div>
</div>
@@ -471,12 +471,12 @@ configuration.add(ComponentParameterCons
<p>You contribution would look like:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public static void contributeIgnoredPathsFilter(Configuration<String>
configuration)
{
configuration.add("/dwr/.*");
}
-]]></script>
+</pre>
</div></div>
<p>The regular expression matches any path that begins with "/dwr/".</p>
@@ -499,15 +499,15 @@ configuration.add(ComponentParameterCons
<p>1. Add the parameter to your JVM command line:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
-Dtapestry.execution-mode=DevelopmentMode jetty:run
-]]></script>
+</pre>
</div></div>
<p>2. Add the parameter to the Jetty plugin:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>pom.xml</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
@@ -524,13 +524,13 @@ configuration.add(ComponentParameterCons
</systemProperties>
</configuration>
</plugin>
-]]></script>
+</pre>
</div></div>
<p>3. Add the parameter to the Surfire plugin for your test:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>pom.xml</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
@@ -541,7 +541,7 @@ configuration.add(ComponentParameterCons
</systemPropertyVariables>
</configuration>
</plugin>
-]]></script>
+</pre>
</div></div>
<p>For each mode declared in your JVM System Property, TapestryFilter checks
for a parameter in your web.xml, named tapestry.TheModeName-modules, with
TheModeName being the name of the desired mode. Its value will be a
comma-separated list of modules.</p>
@@ -551,7 +551,7 @@ configuration.add(ComponentParameterCons
<p>The example below defines two differents execution modes in your web.xml
file: production (the default value) and DevelopmentMode. For each mode, we
list the modules we want to load. If we use JVM System property declared in the
example above, the DevelopmentModeModule module will be loaded.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>web.xml</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<context-param>
<param-name>tapestry.production-modules</param-name>
<param-value>org.apache.tapestry.appli.services.ProductionModeModule</param-value>
@@ -560,21 +560,21 @@ configuration.add(ComponentParameterCons
<param-name>tapestry.DevelopmentMode-modules</param-name>
<param-value>org.apache.tapestry.appli.services.DevelopmentModeModule</param-value>
</context-param>
-]]></script>
+</pre>
</div></div>
<p>Tapestry will load modules in the order that they are declared. For
example, if we run the following command line:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
-Dtapestry.execution-mode=DevelopmentMode,DevelopmentMode2 jetty:run
-]]></script>
+</pre>
</div></div>
<p>and then for each modes we have two modules:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>web.xml</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<context-param>
<param-name>tapestry.DevelopmentMode-modules</param-name>
<param-value>
@@ -589,7 +589,7 @@ configuration.add(ComponentParameterCons
org.apache.tapestry.appli.services.DevelopmentMode2Module2
</param-value>
</context-param>
-]]></script>
+</pre>
</div></div>
<p>then Tapestry will load modules in the order: DevelopmentMode1Module1,
DevelopmentMode1Module2, DevelopmentMode2Module1 and DevelopmentMode2Module2</p>
@@ -613,18 +613,18 @@ configuration.add(ComponentParameterCons
<p>So, if you wanted to run the Tapestry application inside folder
<tt>t5app</tt>, you would modify your <tt>web.xml</tt> indicate the use of the
folder:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
<filter-mapping>
<filter-name>app</filter-name>
<url-pattern>/t5app/*</url-pattern>
</filter-mapping>
-]]></script>
+</pre>
</div></div>
<p>... and in your AppModule, you would inform Tapestry about the mapping
change:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class AppModule
{
@Contribute(SymbolProvider.class)
@@ -634,7 +634,7 @@ public class AppModule
configuration.add(SymbolConstants.APPLICATION_FOLDER, "t5app")
}
}
-]]></script>
+</pre>
</div></div>
<div class="panelMacro"><table class="infoMacro"><colgroup span="1"><col
span="1" width="24"><col span="1"></colgroup><tr><td colspan="1" rowspan="1"
valign="top"><img align="middle" src="/images/confluence/information.gif"
width="16" height="16" alt="" border="0"></td><td colspan="1" rowspan="1">This
extra mapping is unfortunately necessary, because the Servlet API does not
provide a way for a servlet filter, such as the one used by Tapestry, to know
about its mapping.</td></tr></table></div>
Modified: websites/production/tapestry/content/session-storage.html
==============================================================================
--- websites/production/tapestry/content/session-storage.html (original)
+++ websites/production/tapestry/content/session-storage.html Sun Sep 15
19:16:07 2013
@@ -91,7 +91,7 @@
<p>Example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class MyPage
{
@SessionState
@@ -99,7 +99,7 @@ public class MyPage
. . .
}
-]]></script>
+</pre>
</div></div>
<p>Any other component or page that declares a field <b>of the same type</b>,
regardless of name, and marks it with the SessionState annotation will share
the same value. It's that simple. However, using @SessionState <em>safely</em>
requires care:</p>
@@ -117,7 +117,7 @@ public class MyPage
<p>With @SessionState, you are creating a session-wide data storage area that
is tied to the <em>type</em> (class) of the variable you annotate. It is not
specifically tied to the variable itself, or even to the class in which that
variable was annotated. As with all session data, there is the serious
possibility of collisions, not just within your application but with other
modules/libraries:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>Example of Data Collision
– Don't Do This!</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
@SessionState
private String userName; // Unsafe -- String is not a custom type
@@ -125,7 +125,7 @@ public class MyPage
@sessionState
private String userCity; // This overwrites value in userName, because
it's also a String!
-]]></script>
+</pre>
</div></div>
<p>The simple rule is, NEVER use @SessionState for simple-type variables. It
is ALWAYS worth taking the time to build a special class to hold your session
state information. Doing so will force you to consolidate that information into
a single, logical unit that can't be accidentally accessed by other classes.
(Alternatively, see the Session Attribute section below.)</p>
@@ -139,9 +139,9 @@ public class MyPage
<p>Instead, create a second field with a matching name but with "Exists"
appended:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
private boolean shoppingCartExists;
-]]></script>
+</pre>
</div></div>
<p>It is not annotated; it is located by naming convention ("Exists"
appended). It must be type boolean and must be a private instance variable.
Tapestry will automatically set this variable to <tt>true</tt> when the SSO is
created, so you can check it to see if the SSO already exists.</p>
@@ -149,10 +149,10 @@ public class MyPage
<p>Alternately, you may allow for the state being null:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
@SessionState(create=false)
private ShoppingCart shoppingCart;
-]]></script>
+</pre>
</div></div>
<p>In this case, the shoppingCart field will be null if the ShoppingCart SSO
does not exist, but will be non-null if it has been created (either by
assigning a value to the field, or by a different SSO field where create is
true).</p>
@@ -172,7 +172,7 @@ public class MyPage
<p>A Session State Object is configured using contributions to the
ApplicationStateManager service. From your application's module:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public void contributeApplicationStateManager(MappedConfiguration<Class,
ApplicationStateContribution> configuration)
{
ApplicationStateCreator<MyState> creator = new
ApplicationStateCreator<ShoppingCart>()
@@ -185,7 +185,7 @@ public class MyPage
configuration.add(ShoppingCart.class, new
ApplicationStateContribution("session", creator));
}
-]]></script>
+</pre>
</div></div>
<p>Here, we have an SSO type of ShoppingCart, and we're providing a creator
for it. We've dolled the creator up with some generic types, but that isn't
essential.</p>
@@ -206,7 +206,7 @@ public class MyPage
<p>As an alternative to SSOs, Tapestry provides a <b>Session Attribute</b>
mechanism, which lets you store data in the session by name (rather than type).
It is particularly useful when integrating Tapestry with legacy applications
that directly manipulate the HttpSession.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>The Old Way</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class Page {
@Inject
private Request request;
@@ -215,29 +215,29 @@ public class Page {
return (User)
request.getSession(true).getAttribute("loggedInUserName");
}
}
-]]></script>
+</pre>
</div></div>
<p>Starting with Tapestry 5.2, this can be accomplished just by annotating a
page or component property with @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionAttribute.html">SessionAttribute</a>.
This annotation is used to map a property of a page or component to value
stored in session. Unlike Session State Objects, the name (not the type) of the
annotated property is used as the name of the session attribute to look for.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>The New Way</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class Page {
@SessionAttribute
private User loggedInUserName;
}
-]]></script>
+</pre>
</div></div>
<p>You can also provide a name using the annotation's <tt>value</tt>
parameter:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class Page {
@SessionAttribute("loggedInUserName")
private User userName;
}
-]]></script>
+</pre>
</div></div>
@@ -248,7 +248,7 @@ public class Page {
<p>It's best to define the session attribute name as constant, and use that in
the annotation's value parameter, rather then defaulting to the instance
variable name. This will help prevent subtle runtime errors due to
misspellings. For example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>The Safer Way</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public static final String USER_NAME_SESSION_ATTRIBUTE =
"com.example.shoppingapp.username";
...
@@ -257,7 +257,7 @@ public class Page {
@SessionAttribute(USER_NAME_SESSION_ATTRIBUTE)
private User userName;
}
-]]></script>
+</pre>
</div></div>
<h2><a shape="rect" name="SessionStorage-ClusteringIssues"></a>Clustering
Issues</h2>
@@ -296,13 +296,13 @@ are stored in the session and shared bet
<p>The <tt>tapestry.session-locking-enabled</tt> <a shape="rect"
href="configuration.html" title="Configuration">symbol</a> can control this
behavior. Setting this to true (the default) will yield a more robust
application; setting it to false may speed up processing for more Ajax
intensive applications (but care should then be given to ensuring that objects
shared inside the session are themeselves immutable or thread-safe).</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>AppModule.java
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public static void
contributeApplicationDefaults(MappedConfiguration<String,String>
configuration)
{
configuration.add(SymbolConstants.SESSION_LOCKING_ENABLED, true);
...
}
-]]></script>
+</pre>
</div></div>
</div>
</div>
Modified: websites/production/tapestry/content/switching-cases.html
==============================================================================
--- websites/production/tapestry/content/switching-cases.html (original)
+++ websites/production/tapestry/content/switching-cases.html Sun Sep 15
19:16:07 2013
@@ -79,7 +79,7 @@ table.ScrollbarTable td.ScrollbarNextIco
<p>Imagine for example a use case, where you want to distinguish between 4
cases and you have an int property called <tt>whichCase</tt> that should be
tested against. Your page template would look as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SwitchMe.tml</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
<body>
<h1>Switch</h1>
@@ -103,13 +103,13 @@ table.ScrollbarTable td.ScrollbarNextIco
</t:block>
</body>
</html>
-]]></script>
+</pre>
</div></div>
<p>You can see, that the <tt>Delegate</tt> component's <tt>to</tt> parameter
is bound to the case property of your page class. In your page class you
therefore have a <tt>getCase()</tt> method that is responsible for telling the
<tt>Delegate</tt> component which component should be rendered. For that we are
injecting references to the <tt>Block}}s defined in your page template into the
page class and return the according {{Block</tt> in the <tt>getCase()</tt>
method.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SwitchMe.java</b></div><div
class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class SwitchMe
{
@Persist
@@ -135,7 +135,7 @@ public class SwitchMe
}
}
}
-]]></script>
+</pre>
</div></div>
<p>Happy switching!</p></div>
Modified: websites/production/tapestry/content/tapestry-for-jsf-users.html
==============================================================================
--- websites/production/tapestry/content/tapestry-for-jsf-users.html (original)
+++ websites/production/tapestry/content/tapestry-for-jsf-users.html Sun Sep 15
19:16:07 2013
@@ -119,23 +119,23 @@ table.ScrollbarTable td.ScrollbarNextIco
<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0"
width="100%"><tbody><tr><td colspan="1" rowspan="1" valign="top"
class="confluenceTd">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>JSF template
(helloworld.xhtml)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<p><h:outputText value="#{helloWorldBean.greeting} /></p>
</h:body>
</html>
-]]></script>
+</pre>
</div></div></td><td colspan="1" rowspan="1" valign="top" class="confluenceTd">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>Tapestry template
(HelloWorld.tml)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-xml">
<html>
<body>
<p>${greeting}</p>
</body>
</html>
-]]></script>
+</pre>
</div></div></td></tr></tbody></table>
<p>Though these are very similar, notice some differences:</p>
@@ -144,7 +144,7 @@ table.ScrollbarTable td.ScrollbarNextIco
<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0"
width="100%"><tbody><tr><td colspan="1" rowspan="1" valign="top"
class="confluenceTd">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>JSF Backing Bean
(HelloWorldBean.java)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
@ManagedBean
@RequestScoped
public class HelloWorldBean {
@@ -152,16 +152,16 @@ public class HelloWorldBean {
return "Hello, World!";
}
}
-]]></script>
+</pre>
</div></div></td><td colspan="1" rowspan="1" valign="top" class="confluenceTd">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>Tapestry page class
(HelloWorld.java)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class HelloWorld {
public String getGreeting() {
return "Hello, World!";
}
}
-]]></script>
+</pre>
</div></div></td></tr></tbody></table>
<h2><a shape="rect"
name="TapestryforJSFUsers-Expressionsintemplates"></a>Expressions in
templates</h2>
@@ -186,12 +186,12 @@ public class HelloWorld {
<p>Tapestry applications can use JSR 303 Bean Validation annotations that JSF
users should be familiar with:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class Employee {
@Validate("required,minlength=2,maxlength=100")
private String lastName;
@NotNull @Email private String email;
-]]></script>
+</pre>
</div></div>
<h3><a shape="rect"
name="TapestryforJSFUsers-PostRedirectGetNavigation"></a>Post-Redirect-Get
Navigation</h3>
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 Sun Sep
15 19:16:07 2013
@@ -72,9 +72,9 @@ table.ScrollbarTable td.ScrollbarNextIco
<p>The documentation for the <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select
Component</a> and the <a shape="rect" href="tutorial.html"
title="Tutorial">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
shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a>
and a <a shape="rect" 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" style="border-width: 1px;"><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
<t:select t:id="colorMenu" value="selectedColor" model="ColorSelectModel"
encoder="colorEncoder" />
-]]></script>
+</pre>
</div></div>
<p>In the above example, ColorSelectModel must be of type SelectModel, or
anything that Tapestry knows how to <a shape="rect" href="type-coercion.html"
title="Type Coercion">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>
@@ -92,7 +92,7 @@ table.ScrollbarTable td.ScrollbarNextIco
<p>To have Tapestry create a SelectModel for you, use the <a shape="rect"
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" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a
page class)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
@Property
private SelectModel colorSelectModel;
@Inject
@@ -105,19 +105,19 @@ void setupRender() {
// create a SelectModel from my list of colors
colorSelectModel = selectModelFactory.create(colors, "name");
}
-]]></script>
+</pre>
</div></div>
<p>The resulting SelectModel has a selectable option (specifically, an
OptionModel) for every object in the original List. The label property name
(the "name" property, in this example) determines the user-visible text of each
menu option, and your ValueEncoder's toClient() method provides the encoded
value (most commonly a simple number). If you don't provide a ValueEncoder, the
result of the objects' toString() method (Color#toString() in this example) is
used. Although not a recommended practice, you <em>could</em> set your
toString() to return the object's ID for this purpose:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>Color.java
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
...
@Override
public String toString() {
return String.valueOf(this.getId());
}
-]]></script>
+</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>
@@ -136,7 +136,7 @@ public String toString() {
<p>That's exactly what you should do in your own ValueEncoders too:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in
your com.example.myappname.encoders package)</b></div><div class="codeContent
panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
public class ColorEncoder implements ValueEncoder<Color>,
ValueEncoderFactory<Color> {
@Inject
@@ -160,13 +160,13 @@ public class ColorEncoder implements Val
return this;
}
}
-]]></script>
+</pre>
</div></div>
<p>Alternatively, if you don't expect to need a particular ValueEncoder more
than once in your app, you might want to just create it on demand, using an
anonymous inner class, from the getter method in the component class where it
is needed. For example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a
page class, partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
. . .
public ValueEncoder<Color> getColorEncoder() {
@@ -186,7 +186,7 @@ public class ColorEncoder implements Val
}
};
}
-]]></script>
+</pre>
</div></div>
<p>Notice that the body of this anonymous inner class is the same as the body
of the ColorEncoder top level class, except that we don't need a
<tt>create</tt> method.</p>
@@ -196,19 +196,19 @@ public class ColorEncoder implements Val
<p>If your ValueEncoder <em>implements ValueEncoderFactory</em> (as the
ColorEncoder top level class does, above), you can associate your custom
ValueEncoder with your entity class so that Tapestry will automatically use it
every time a ValueEncoder is needed for items of that type (such as with the
Select, RadioGroup, Grid, Hidden and AjaxFormLoop components). Just add lines
like the following to your module class (usually AppModule.java):</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>AppModule.java
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
...
public static void
contributeValueEncoderSource(MappedConfiguration<Class<Color>,
ValueEncoderFactory<Color>> configuration) {
configuration.addInstance(Color.class, ColorEncoder.class);
}
-]]></script>
+</pre>
</div></div>
<p>If you are contributing more than one ValueEncoder, you'll have to use raw
types, like this:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>AppModule.java
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
...
public static void
contributeValueEncoderSource(MappedConfiguration<Class,
ValueEncoderFactory> configuration)
@@ -216,7 +216,7 @@ public class ColorEncoder implements Val
configuration.addInstance(Color.class, ColorEncoder.class);
configuration.addInstance(SomeOtherType.class,
SomeOtherTypeEncoder.class);
}
-]]></script>
+</pre>
</div></div>
@@ -225,19 +225,19 @@ public class ColorEncoder implements Val
<p>The Select component's "encoder" parameter is optional, but if the "value"
parameter is bound to a complex object (not a simple String, Integer, etc.) and
you don't provide a ValueEncoder with the "encoder" parameter (and one isn't
provided automatically by, for example, the Tapestry Hibernate integration),
you'll receive a "Could not find a coercion" exception (when you submit the
form) as Tapestry tries to convert the selected option's encoded value back to
the <em>object</em> in your Select's "value" parameter. To fix this, you'll
either have to 1) provide a ValueEncoder, 2) provide a <a shape="rect"
href="typecoercer-service.html" title="TypeCoercer Service">Coercion</a>, or 3)
use a simple value (String, Integer, etc.) for your Select's "value" parameter,
and then you'll have to add logic in the corresponding onSuccess event listener
method:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SelectWithListDemo.tml
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
<t:select t:id="colorMenu" value="selectedColorId" model="ColorSelectModel"
/>
-]]></script>
+</pre>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java
(partial)</b></div><div class="codeContent panelContent">
-<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<pre class="code-java">
...
public void onSuccessFromMyForm() {
// look up the color object from the ID selected
selectedColor = colorService.findById(selectedColorId);
...
}
-]]></script>
+</pre>
</div></div>
<p>But then again, you may as well create a ValueEncoder instead.</p>