Selecting from a list of entities
See http://docs.jboss.org/seam/latest/reference/en/html/controls.html
- Use <s:selectItems> to produce a list of labeled select items from a list of entities.
- Use <s:convertEntity> to map back and forth between the select items and the actual entity values. This is what allows you to map the value of the <h:selectOneMenu> directly to the property of the referencing entity (e.g. a property that is a many-to-one).
<h:selectOneMenu value="#{person.continent}" required="true"> (1) <s:selectItems value="#{continents.resultList}" var="continent" (2) label="#{continent.name}" noSelectionLabel="Please Select..."/> <s:convertEntity /> (3) </h:selectOneMenu>
- person is an entity that has been outjected into the conversation. It has a 'continent' property which is many-to-one association with another entity.
- continents is a Seam application framework 'query' object. This 'query' object should probably use a Seam-managed EntityManager because we want have the Hibernate session-in-view behavior so we don't get lazy initialization exceptions when rendering the labels, etc.
- s:convertEntity will convert the Continent entities into values for the HTML select, and vice versa.
Tips
- To avoid LazyInitializationExceptions and/or writing extra code in your EJB/Controller bean to initialize objects, use session in view.
- For required fields, put required="true" on the selectOneMenu and override javax.faces.component.UIInput.REQUIRED in messages.properties (see Standard Faces Error Messages).
Select from an enum
This works just like selecting an entity, but <s:convertEnum/> is used instead.
XHTML:
<h:selectOneMenu id="marketStatus" value="#{person.status}" (1) required="true"> <s:selectItems value="#{enumLists.statusArray}" var="status" (2) label="#{status}" noSelectionLabel="Select a status..."/> <s:convertEnum/> </h:selectOneMenu>
EnumLists.java:
@Name("enumLists") @Scope(ScopeType.STATELESS) public class EnumLists { public Status[] getStatusArray() { return Status.values(); } }
- person is an entity that has been outjected into the conversation. It has a 'status' property which is an enum.
- We need to expose the values of the enum as a list or an array, so we make a stateless POJO component with getters that returns arrays for various enums called enumLists.
Multi-select from an enum
Here we use a selectManyCheckbox.
<h:selectManyCheckbox id="roles" layout="pageDirection" value="#{person.roles}" required="true"> <s:selectItems value="#{enumLists.roleArray}" var="role" label="#{role}"/> <s:convertEnum/> </h:selectManyCheckbox>
Unfortunately, Seam's convertEnum< can't handle multi selects yet. This example will yeild a strange exception:
java.lang.IllegalArgumentException: java.util.List is not an enum type
Luckily, it's very easy to create Custom converter tags with Facelets. Here is the converter class that handles both ordinary enums and multi-selects:
package eg; import javax.faces.component.*; import javax.faces.context.*; import javax.faces.convert.*; import javax.faces.el.ValueBinding; import java.util.List; import java.util.Collection; /** * Converter for enum multi-selects. * <br>User: Joshua Davis * Date: May 16, 2007 * Time: 7:25:58 AM */ public class EnumListConverter implements Converter { @SuppressWarnings({"unchecked"}) public Object getAsObject(FacesContext context, UIComponent comp, String value) throws ConverterException { ValueBinding binding = comp.getValueBinding("value"); Class enumType = binding.getType(context); if (enumType.isEnum()) // Single enum? return Enum.valueOf(enumType, value); else // List of enums. { // Find the s:selectItems so we can get the enum. List children = comp.getChildren(); for (Object child : children) { if (child instanceof UIComponent) { UIComponent c = (UIComponent) child; ValueBinding b = c.getValueBinding("value"); Class t = b.getType(context); // Array of enums: use the component type. if (t.isArray() && t.getComponentType().isEnum()) { t = t.getComponentType(); return Enum.valueOf(t,value); } else { Object v = b.getValue(context); // Collection of enum values, get the type of the first element. if (v instanceof Collection) { t = ((Collection) v).iterator().next().getClass(); return Enum.valueOf(t,value); } } } } throw new ConverterException("Unable to find selectItems with enum values!"); } } public String getAsString(FacesContext context, UIComponent component, Object object) throws ConverterException { if (object == null) { return null; } return ((Enum) object).name(); } }
Add Comment