This Confluence has been LDAP enabled, if you are an ASF Committer, please use your LDAP Credentials to login. Any problems file an INFRA jira ticket please.

Child pages
  • Using Select With a List

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Wiki Markup
{scrollbar}

Excerpt
hiddentrue

Using SelectModel, SelectModelFactory and ValueEncoder for Select menus populated from a database

Using Select With a List

The documentation for the Select Component and the Tapestry Tutorial provide simplistic examples of populating a drop-down menu (as the (X)HTML Select 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 SelectModel and a ValueEncoder bound to the Select component with its "model" and "encoder" parameters:

Code Block

<t:select t:id="colorMenu" value="selectedColor" model="ColorSelectModel" encoder="colorEncoder" />

In the above example, ColorSelectModel must be of type SelectModel, or anything that Tapestry knows how to coerce 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.

SelectModel

Wiki Markup
{float:right|background=#eee|padding=0 1em}
    *JumpStart Demos:*
    [Total Control Object Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject]
    [ID Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id]
    [Easy ID Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid]
{float}
A SelectModel is a collection of options (specifically OptionModel objects) for a drop-down menu. Basically, each option is a value (an object) and a label (presented to the user).

...

Code Block
titleSelectWithListDemo.java (a page class)

@Property
private SelectModel colorSelectModel;
@Inject
SelectModelFactory selectModelFactory;
...
void setupRender() {
    // invoke my service to find all colors, e.g. in the database
    List<Color> colors = colorService.findAll();

    // create a SelectModel from my list of colors
    colorSelectModel = selectModelFactory.create(colors, "name");
}

...

Code Block
titleColor.java (partial)

...
@Override
public String toString() {
    return String.valueOf(this.getId()); 
}

...

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 and 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.

Wiki Markup
{float:right|background=#eee|padding=0 1em}
    *JumpStart Demo:*
    [Easy Object Select|http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyobject]
{float}
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 object matching the given ID by doing a database lookup (ideally using a service or DAO method).

...

Code Block
titleColorEncoder.java (perhaps in your com.example.myappname.encoders package)

public class ColorEncoder implements ValueEncoder<Color>, ValueEncoderFactory<Color> { 

    @Inject
    private ColorService colorService;

    @Override
    public String toClient(Color value) {
        // return the given object's ID
        return String.valueOf(value.getId()); 
    }

    @Override
    public Color toValue(String id) { 
        // find the color object of the given ID in the database
        return colorService.findById(Long.parseLong(id)); 
    }

    // let this ValueEncoder also serve as a ValueEncoderFactory
    @Override
    public ValueEncoder<Color> create(Class<Color> type) {
        return this; 
    }
} 

...

Code Block
titleSelectWithListDemo.java (a page class, partial)
     . . .

    public ValueEncoder<Color> getColorEncoder() {

        return new ValueEncoder<Color>() {

            @Override
            public String toClient(Color value) {
                // return the given object's ID
                return String.valueOf(value.getId()); 
            }

            @Override
            public Color toValue(String id) { 
                // find the color object of the given ID in the database
                return colorService.findById(Long.parseLong(id)); 
            }
        }; 
    }

...

Code Block
titleAppModule.java (partial)

...
    public static void contributeValueEncoderSource(MappedConfiguration<Class<Color>,
                        ValueEncoderFactory<Color>> configuration) { 
        configuration.addInstance(Color.class, ColorEncoder.class);
    }

...

Code Block
titleAppModule.java (partial)

...
    public static void contributeValueEncoderSource(MappedConfiguration<Class,
                        ValueEncoderFactory> configuration)
    {
        configuration.addInstance(Color.class, ColorEncoder.class);
        configuration.addInstance(SomeOtherType.class, SomeOtherTypeEncoder.class);
    }

...

Code Block
titleSelectWithListDemo.tml (partial)

<t:select t:id="colorMenu" value="selectedColorId" model="ColorSelectModel" />
Code Block
titleSelectWithListDemo.java (partial)

...
    public void onSuccessFromMyForm() {
        // look up the color object from the ID selected
    	selectedColor = colorService.findById(selectedColorId);
    	...
    }

...