my JSF page
You have to use selectitem list in the f:selecitems
attribute of h:selectOneMenu
Your page will be like this;
<h:form>
<h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">
<p:ajax event="change" process="studlist" update="studdep" ></p:ajax>
<f:selectItems value="#{studBean.studentSelectItemList}" />
<f:converter converterId="studentconverter"/>
</h:selectOneMenu>
</h:form>
At the backing bean side you have to fill the studentSelectItemList selectitem.
private List<SelectItem> studentSelectItemList;
//fill studentSelectItemList at the appropriate place
studentSelectItemList.add(new SelectItem(studentId,studentName));
After these settings you should have student id as select value.
Today I had the same problem.
It is caused by this wrong rendering:
<select ...>
<option>None</option>
<option value="1">First</option>
<option value="2">Second</option>
</select>
omitting value=""
for "None" option result in submitting the label instead of an empty string.
However to solve this and make the renderer write value=""
for the first option just make sure getAsString()
never returns null, return ""
(empty string) instead.
@BalusC
<h:form id="form">
...
<p:selectOneMenu id="targetStep" value="#{action.targetStep}" required="true">
<o:converter converterId="omnifaces.ListIndexConverter" list="#{entity.stepList}" />
<f:selectItems var="step" value="#{entity.stepList}" itemLabel="#{step.name}"
itemValue="#{step}" />
</p:selectOneMenu>
<p:commandButton process="@this" update="@widgetVar(stepDialog)"
oncomplete="PF('stepDialog').show()" icon="#{icons.addStep}"
value="#{bundle.addStep}">
<f:setPropertyActionListener target="#{viewScope.step}"
value="#{s:newInstance('it.shape.edea2.jpa.WorkflowStep')}" />
</p:commandButton>
<p:message for="targetStep" />
...
</h:form>
<p:dialog widgetVar="stepDialog" header="#{bundle.addStep}" modal="true" dynamic="true"
resizable="false">
<h:form>
<p:panelGrid columns="2" styleClass="app-full-width">
<h:outputLabel value="#{bundle.name}" />
<h:panelGroup>
<p:inputText id="name" value="#{step.name}" required="true" />
<p:message for="name" />
</h:panelGroup>
...
<f:facet name="footer">
<p:commandButton process="@form" update="@form :form"
oncomplete="hideDialog('stepDialog', args)" icon="#{icons.confirm}"
value="#{bundle.confirm}">
<p:collector value="#{step}" addTo="#{entity.stepList}" />
<f:setPropertyActionListener target="#{action.targetStep}"
value="#{step}" />
</p:commandButton>
</f:facet>
</p:panelGrid>
</h:form>
</p:dialog>
Your omnifaces.ListIndexConverter
to the rescue :)
I'm not sure why you got the item label instead of the item value inside getAsObject()
. Perhaps your getAsString()
is doing it wrong and it is returning student name based on the student ID.
At any way, I can tell that your itemValue
is definitely not right.
<h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">
<f:selectItems value="#{studBean.student}" var="s"
itemValue="#{s.studid}" itemLabel="#{s.name}" />
<f:converter converterId="studentconverter" />
</h:selectOneMenu>
A converter is intented to be used to convert between a complex Java object and a String representation so that it can be passed around as a HTTP request parameter. However, you're specifying the student ID as item value instead of the whole student object. You need to specify the whole student object instead. You should also ensure that #{studBean.selectedStudent}
refers to a Student
property, not some Long
property representing the student ID.
When you fix the itemValue
as follows:
<h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">
<f:selectItems value="#{studBean.student}" var="s"
itemValue="#{s}" itemLabel="#{s.name}" />
<f:converter converterId="studentconverter" />
</h:selectOneMenu>
and your converter as follows (trivial nullchecks omitted):
public String getAsString(FacesContext context, UIComponent component, Object value) {
// This method is called when item value is to be converted to HTTP request parameter.
// Normal practice is to return an unique identifier here, such as student ID.
Student student = (Student) value;
Long id = student.getStudid();
return String.valueOf(id);
}
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// This method is called when HTTP request parameter is to be converted to item value.
// You need to convert the student ID back to Student.
Long id = Long.valueOf(value);
Student student = someStudentService.find(id);
return student;
}
then it ought to work.
Alternatively, you could keep your itemValue
as you initially had and remove the <f:converter>
altogether, but then you have to change #{studBean.selectedStudent}
to point to a Long
property representing the student ID.
BalusC (again) nailed this one for me. I had the same problem and as BalusC pointed out earlier my converter's getAsString() method returned my object's "firstname" property.
@Override public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
}
else {
return String.valueOf(((Employee) value).getfirstname());
}
}
I changed this to return the id and it started working as expected.
@Override public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
}
else {
return String.valueOf(((Employee) value).getId());
}
}
BalusC your effort to explain the theory is hugely appreciated. You're heavensent!