<s:selectItems /> and <s:convertEntity /> output a key based on a numeric sequence to the page. How can I make it output something meaningful (e.g. the natural id of the entity)?
Why would you want to do this? Well, perhaps you want to use do some client side manipulation using JavaScript.
In Seam 2.0.1 I've added two mechanisms for doing this. You'll need to choose one based on your requirement.
By default <s:selectItems value="#{people}"/> uses, as its itemValue (which is rendered as the value attribute on <option />) each item in the list. Perhaps you want to use some associated object (for example, #{person.employeeNumber}). In this case it's as easy as:
<h:selectOneMenu value="#{project.teamLeadEmployeeNumber}">
<s:selectItems value="#{people}" var="person" label="#{person.name}" itemValue="#{person.employeeNumber}" />
</h:selectOneMenu>
Great! But what if you want to use <s:convertEntity /> (which doesn't play nicely with this approach)? Why? Well the value referenced by the itemValue attribute is passed to <s:convertEntity />.
So, there is a second, slightly more complex option, if you want to use <s:convertEntity /> with custom keys - you need to provide a strategy for converting the entity Identifier to the output value and back.
First, override the org.jboss.seam.ui.entityIdentifierStore component:
@Name("org.jboss.seam.ui.entityIdentifierStore")
@Scope(PAGE)
public class MyEntityIdentifierStore extends EntityIdentifierStore {
Then, override the public String put(Identifier identifier, Object entity) method:
public String put(Identifier identifier, Object entity) {
if (entity instanceof Person) {
Person person = (Person) entity;
return "person:" + person.getEmployeeNumber();
} else {
return super.put(identifier, entity);
}
}
Finally, override public Identifier get(String key):
public Identifier get(String key) {
if (key.startsWith("person")) {
String id = key.substring(6, key.length());
return new EntityIdentifier(Person.class, new Long(id));
} else {
return super.get(key);
}
}
}
I've used EntityIdentifier as I'm using JPA, but of course of you could use HibernateEntityIdentifier if you are using plain Hibernate.
I hope you've learnt in this tutorial how to customise <s:selectItems />, BUT I also hope it highlights what I think is one of the most powerful features of Seam - that you can easily override the core components of Seam!
One minor addition. The reason you are able to override the Seam component is because the default precedence of application components (components written by you) is higher than the precedence of framework components (of which EntityIdentifierStore is one). I talk about this quite extensively in Seam in Action.
Hello,
I've followed this example but i can not get it work. Do you know why is it that the component scanner could keep ignoring MyEntityIdentifierStore unless it inherits from AbstractMutable.
I'm using Seam 2.0.1GA and JBoss EAP4.2.
Any clues?
Thank you.
package au.edu.tisc.session;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.framework.EntityIdentifier;
import org.jboss.seam.framework.Identifier;
import org.jboss.seam.ui.converter.entityConverter.EntityIdentifierStore;
import au.edu.tisc.entity.CourseStatus;
@Name("org.jboss.seam.ui.entityIdentifierStore")
@Scope(ScopeType.PAGE)
public class OnlineEntityIdentifierStore extends EntityIdentifierStore {
protected static class LookupEntity {
protected static final String COURSE_STATUS = "CourseStatus";
}
protected static final String SEPARATOR_TOKEN = ":";
@Override
public String put(Identifier identifier, Object entity) {
Object ent = entity;
CourseStatus cs = ((CourseStatus)entity);
if (entity instanceof CourseStatus) {
return LookupEntity.COURSE_STATUS + SEPARATOR_TOKEN + ((CourseStatus)entity).getId();
} else {
return super.put(identifier, entity);
}
}
@Override
public Identifier get(String key) {
if (key.startsWith(LookupEntity.COURSE_STATUS)) {
String id = key.substring((LookupEntity.COURSE_STATUS + SEPARATOR_TOKEN).length(), key.length());
return new EntityIdentifier(CourseStatus.class, new String(id));
} else {
return super.get(key);
}
}
}
Where in the project did you put the OnlineEntityIdentifierStore? It worked for me when it is placed under the session.
<h:outputLabel>Course status<span class="required">*</span></h:outputLabel>
<s:decorate id="courseStatusIdDecoration">
<h:selectOneMenu value="#{courseSysCourseHome.instance.courseStatus}" id="courseStatusId" required="true" requiredMessage="Course status must be selected.">
<s:selectItems value="#{courseSysCourseAction.courseStatusList}" var="cStatus" label="#{cStatus.description}" hideNoSelection="true" noSelectionLabel="Select course status..."/>
<s:convertEntity />
</h:selectOneMenu>
</s:decorate>>
Aart, where in your session did you place the OnlineEntityIdentifierStore? Under seam, entity or some other place?