I'm trying to create a selectOneMenu using primefaces 5.2, the list items are loaded from a database, and their type is an Object which contains other attributes, I wanted to copy the primefaces showcase method (the Advanced one), but the selected value is never assigned, here is my code:
<h:form id="f">
<p:selectOneMenu id="advanced" value="#{expertiseController.selectedExpertise}" converter="expertiseConverter">
<f:selectItems value="#{expertiseController.expertises}" var="exp" itemLabel="#{exp.id}" itemValue="#{exp}" />
<p:ajax update="test" />
</p:selectOneMenu>
<p:outputLabel id="test" value="#{expertiseController.selectedExpertise.id}"/>
</h:form>
the bean:
@Named(value = "expertiseController")
@ViewScoped
public class ExpertiseController implements Serializable {
private Expertise selectedExpertise = new Expertise();
private List<Expertise> expertises = Expertise.getAllExpertiseTypes();
....
getters ..
the Converter:
FacesConverter("expertiseConverter")
public class ExpertiseConverter implements Converter {
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
try {
return Expertise.getById(value);
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
else {
return null;
}
}
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((Expertise) object).getId());
}
else {
return null;
}
}
}
but the outputLabel is never set, and the setter method of the selectedExpertise
is never fired.
Now this only happenes when i set the itemValue to #{exp}
, but when i set it like to #{exp.id}
(and change the selectOneMenu value ofcourse) everything works.
I even checked the converter values, they are both fine.
And the problem is when i try the primefaces example it works well! when i change it to my Object and converter it dosnt!
What am i missing or doing wrong here?
UPDATE:
I just figured out that you have to return in the converter the same object from the list, here s what i did,
I injected the ExpertiseController
in the ExpertiseConverter
, then i loop through the list of the ExpertiseController
and returned the same object (same address i guess or something), here is the code:
import com.medisecretaire.controller.ExpertiseController;
import com.medisecretaire.model.Expertise;
import java.io.Serializable;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.inject.Inject;
@FacesConverter("expertiseConverter")
public class ExpertiseConverter implements Converter, Serializable {
@Inject
private ExpertiseController controller;
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
System.out.println(controller.getExpertises());
if(value != null && value.trim().length() > 0) {
try {
for (Expertise expertise : controller.getExpertises()) {
if(expertise.getId().equalsIgnoreCase(value)){
return expertise;
}
}
return null;
} catch(Exception e) {
return null;
}
}
else {
return null;
}
}
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((Expertise) object).getId());
}
else {
return null;
}
}
}
But is there a better way to do it? i didnt like the "injecting" part ... or is it normal?
UPDATE 2:
when i add filter="true"
it does not work anymore .. this is confusing ...
UPDATE 3:
I knew there was a better way! so i grabbed the UIComponent
extracted the SelectOneMenu
iterated over its children and found the UISelectItems
, from there i found the same objects stored in a list, here is the code:
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
List list = null;
SelectOneMenu menu = (SelectOneMenu) uic;
for (UIComponent comp : menu.getChildren()) {
if (comp instanceof UISelectItems) {
UISelectItems item = (UISelectItems) comp;
if (item.getValue() instanceof List) {
list = (List) item.getValue();
}
}
}
//Do something with the list
and ever with the filer attribute it works now.