| <document> |
| <body> |
| <section name="Simple Example"> |
| |
| <p> |
| A simple example, selecting one of three strings: |
| </p> |
| |
| <subsection name="SelectColor.tml"> |
| <source><![CDATA[ |
| <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> |
| <body> |
| <h1>Select Color</h1> |
| |
| <t:form> |
| |
| <t:label for="color"/>: |
| <t:select t:id="color" model="literal:Red,Green,Blue"/> |
| |
| <br/> |
| |
| <input type="submit" value="Continue"/> |
| </t:form> |
| |
| </body> |
| </html>]]></source> |
| |
| <p> |
| When the model parameter is a string, it is split apart at the commas. When the model parameter is |
| a List of Strings, each element is considered a selection option. |
| </p> |
| |
| <p> |
| When using this approach, you'll commonly put the list into the message catalog, |
| and reference it using a "message:" binding. |
| </p> |
| |
| <p> |
| Here the label displayed to the user is the same as the value used to update the property, but that |
| doesn't have to be the case. By specifying a value and a label, we can control the server side value |
| without changing how the UI appears to the user: |
| </p> |
| |
| <source> |
| <![CDATA[ |
| <t:select t:id="color" model="literal:FF0000=Red,00FF00=Green,0000FF=Blue"/> |
| ]]> |
| </source> |
| |
| |
| </subsection> |
| |
| <subsection name="SelectColor.java"> |
| |
| <source><![CDATA[ |
| public class SelectColor |
| { |
| @Validate("required") |
| public String color; |
| |
| }]]></source> |
| |
| <p> |
| Placing the @Validate annotation on the field supplies the default validation for this field, here |
| it indicates that color is required. This prevents the |
| Select component from including a blank option for the field (though this behavior too can be overridden). |
| Without the @Validate, it would be possible for the user to select a blank value, and null would |
| be assigned to the color property of SelectColor. This might be appropriate for a search form, but |
| not for an edit form. |
| </p> |
| |
| </subsection> |
| |
| </section> |
| |
| <section name="Enum Example"> |
| |
| <p>Working with Enums is, amazingly, even easier (and more so than with the Radio component).</p> |
| |
| <p> |
| Most of this example is the same as for the |
| <a href="Radio.html">Radio</a> |
| component, except that |
| we're using a single Select component instead of multiple Radio components: |
| </p> |
| |
| <p> |
| <img src="select_ref2.png"/> |
| </p> |
| |
| <subsection name="CardType.java"> |
| |
| <source><![CDATA[ |
| public enum CardType |
| { |
| MASTER_CARD, VISA, AMERICAN_EXPRESS, DINERS_CLUB, DISCOVER |
| } |
| ]]></source> |
| |
| </subsection> |
| |
| <subsection name="Payment.tml (partial)"> |
| |
| <p> |
| In the Radio example, we used a Label and a Radio component for each enum value. |
| With Select we use a single Label and a single Select component: |
| </p> |
| |
| <source><![CDATA[ |
| <t:label for="type"/>: |
| <t:select t:id="type"/>]]></source> |
| |
| |
| <p> |
| Here again, Tapestry is binding the value parameter to the type property, based on the component's |
| id. |
| In addition, because the property type of the property in question is an enum, a SelectModel |
| is automatically generated. |
| </p> |
| |
| </subsection> |
| |
| <subsection name="Payment.java (partial)"> |
| |
| <source><![CDATA[ |
| public class Payment |
| { |
| . . . |
| |
| @Property |
| @Persist |
| @Validate("required") |
| private CardType type; |
| |
| |
| . . . |
| }]]></source> |
| |
| |
| </subsection> |
| |
| <subsection name="Payment.properties"> |
| |
| <p> |
| Once again, we need to slightly customize Tapestry's guess at the label for the enum value |
| DINERS_CLUB. |
| In the Radio example, we overrode the label for the dinersClub<em>component</em>. Here there is just |
| the Select component, |
| but we still have an option: override how the DINERS_CLUB enum value is displayed: |
| </p> |
| |
| <source><![CDATA[DINERS_CLUB=Diner's Club]]></source> |
| |
| <p>Tapestry looks inside a component's message catalog for entries before "humanizing" the name. In the |
| <em>very rare</em> |
| event that there's a naming conflict, you may qualify the enum value with its class name: |
| </p> |
| |
| |
| <source><![CDATA[CardType.DINERS_CLUB=Diner's Club]]></source> |
| |
| <p>And, of course, all of this is case insensitive. The use of case here helps to identify how the |
| values |
| are to be used. |
| </p> |
| </subsection> |
| |
| </section> |
| |
| <section name="Chaining of Select components"> |
| There is often a requirement for chaining Select components. When a value of a Select component is changed |
| another Select should become visible. Let's consider the following example: you create an online shop for a car seller. |
| A make is modeled as enumeration CarMaker. |
| |
| <subsection name="CarMaker.java"> |
| <source><![CDATA[ |
| public enum CarMaker |
| { |
| MERCEDES, AUDI, BMW; |
| }]]></source> |
| </subsection> |
| |
| <subsection name="SelectZoneDemo.tml"> |
| The Select component 'carMaker' of the page SelectZoneDemo shows all available car makers. |
| When a user selects a car maker, another Select component for selecting available models of the make should appear. |
| This can be accomplished with the <em>zone</em> parameter of the 'carMaker' Select component. |
| When the <em>zone</em> parameter is bound, every change of the Select's value causes an Ajax |
| request, firing the <em>valueChanged</em> event. In this example, a corresponding event handler |
| method, onValueChanged, populates the <em>model</em> used by the second Select component. |
| <source><![CDATA[ |
| <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> |
| <t:form> |
| <p> |
| <t:errors /> |
| </p> |
| <p> |
| <t:select t:id="carMaker" validate="required" |
| zone="modelZone" /> |
| </p> |
| |
| <t:zone t:id="modelZone" id="modelZone"> |
| <t:if test="carMaker"> |
| <p> |
| <t:select t:id="carModel" model="availableModels" validate="required"/> |
| </p> |
| </t:if> |
| </t:zone> |
| |
| <p> |
| <t:submit value="literal:Submit" /> |
| </p> |
| </t:form> |
| |
| </html>]]></source> |
| </subsection> |
| |
| <subsection name="SelectZoneDemo.java"> |
| The event handler method for the event <em>valuechanged</em> is used to provide the available car models of the currently selected car maker. |
| The new Select's value is passed as context. |
| <source><![CDATA[ |
| public class SelectZoneDemo |
| { |
| |
| @Inject |
| private Messages messages; |
| |
| @Property |
| @Persist |
| private CarMaker carMaker; |
| |
| @Property |
| @Persist |
| private String carModel; |
| |
| @InjectComponent |
| private Zone modelZone; |
| |
| @Property |
| @Persist |
| private List<String> availableModels; |
| |
| public Object onValueChanged(CarMaker maker) |
| { |
| availableModels = findAvailableModels(maker); |
| |
| return modelZone.getBody(); |
| } |
| |
| public List<String> findAvailableModels(final CarMaker maker) |
| { |
| switch (maker) |
| { |
| case AUDI: |
| return Arrays.asList("A4", "A6", "A8"); |
| case BMW: |
| return Arrays.asList("3 Series", "5 Series", "7 Series"); |
| case MERCEDES: |
| return Arrays.asList("C-Class", "E-Class", "S-Class"); |
| default: |
| return Arrays.asList(); |
| } |
| } |
| }]]></source> |
| |
| |
| <p> |
| The Select component is very smart for enum types; it can automatically create a SelectModel for a given Enum, and a default |
| ValueEncoder. Likewise, it can turn an array or List into a SelectModel automatically. This streamlines the use of the Select |
| in many situations ... but because the model and encode parameters are still present, allows you to override its behavior |
| when needed. |
| </p> |
| |
| </subsection> |
| |
| </section> |
| |
| </body> |
| </document> |