Primefaces pickList with inputText not working - jsf

I'm trying to add an inputText field to my primefaces pickList, but I've got some problems with it.
At first: I can't write in the textField with a normal left-click. I have to right click to be able to type in the textField.
Second: It doesn't seem to save the value from the textField to the corresponding entity.
My case:
<h:form id="pickListForm">
<p:pickList converter="primeFacesPickListConverter" id="pickList" value="#{locodeBackingBean.locodes}"
var="locode" showCheckbox="true"
itemValue="#{locode.id}">
<f:facet name="sourceCaption">#{msgs['locode.not.infected']}</f:facet>
<f:facet name="targetCaption">#{msgs['locode.infected']}</f:facet>
<p:column style="width:70%;">
<h:outputText value="#{locode.description}"/>
</p:column>
<p:column style="width:30%">
<p:inputText value="#{locode.incubationPeriod}"/>
</p:column>
</p:pickList>
<p:commandButton value="#{msgs.save}" action="#{locodeBackingBean.save()}" update="growl"/>
</h:form>
My backing bean:
#ManagedBean
#ViewScoped
public class LocodeBackingBean implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private transient LocodeRepositoryBean locodeRepository;
private DualListModel<Locode> locodes = new DualListModel<>();
public void save() {
for (Locode locode : locodes.getTarget()) {
locode.setInfectedArea(true);
locodeRepository.save(locode);
}
for (Locode locode : locodes.getSource()) {
locode.setInfectedArea(false);
locodeRepository.save(locode);
}
addFacesMessage("locode.action.saved");
}
#PostConstruct
public void search() {
List<Locode> source = locodeRepository.findAllNotInfected(locodeSearchCriteria);;
List<Locode> target locodeRepository.findAllInfected(locodeSearchCriteria);
locodes.setSource(source);
locodes.setTarget(target);
}
public DualListModel<Locode> getLocodes() {
return locodes;
}
public void setLocodes(DualListModel<Locode> locodes) {
this.locodes = locodes;
}
And to be complete, my converter:
#FacesConverter(value = "primeFacesPickListConverter")
public class PrimeFacesPickListConverter<T extends Domain> implements Converter {
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
if (arg1 instanceof PickList) {
Object dualList = ((PickList) arg1).getValue();
DualListModel dl = (DualListModel) dualList;
for (Object o : dl.getSource()) {
if (equalsById(arg2, o)) return o;
}
for (Object o : dl.getTarget()) {
if (equalsById(arg2, o)) return o;
}
}
throw new PrimeFacesPickListConverterException("Could not match object's id (" + arg2 + ") to any id's in the list.");
}
private boolean equalsById(String arg2, Object o) {
String id = String.valueOf((((T) o)).getId());
return arg2.equals(id);
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
return String.valueOf(arg2);
}
using PrimeFaces 5.2

Picklists in general are not intended to contain 'controls'. So it was never designed to work this way and if it does not work, that is just unfortunate. Redesigning your ui is the only thing to do.

Related

Why selected items is always empty in the Bean for Primefaces selectCheckboxMenu

I am using selectCheckboxMenu from Primefaces in a JSF project, the problem is that the "selectedDepartments" object in the Bean is always empty.
Here is the code:
Xhtml Page
<p:selectCheckboxMenu id="menu" label="name" style="width: 15rem" converter="#{departmentConverter}" value="#{StudentMB.selectedDepartments}"
multiple="true" filter="true" filterMatchMode="startsWith" panelStyle="width: 15rem" scrollHeight="250" >
<c:selectItems value="#{StudentMB.departmentList}" var="department" itemLabel="#{department.name}" itemValue="#{department}"/>
<p:ajax event="change" process="#this" update=":form2:dt-Students" global="false"/>
</p:selectCheckboxMenu>
The converter for selectCheckboxMenu:
#Named
#FacesConverter(value = "departmentConverter")
public class departmentConverter implements Converter {
#Inject
private departmentDAO departmentDAO;
#Override
public department getAsObject(FacesContext context, UIComponent component, String value) {
if (value != null && value.trim().length() > 0) {
try {
department c= departmentDAO.getdepartmentById(Integer.parseInt(value));
return c;
}
catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid country."));
}
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null) {
department c=(department)value;
return String.valueOf(c.getId());
}
else {
return null;
}
}
}
The code of the Managed Bean
public class StudentMB implements Serializable{
private LazyDataModel<Student> lazyModel = null;
private List<department> departmentList;
private List<department> selectedDepartments;
#Inject
private departmentDAO departmentDAO;
#PostConstruct
public void init() {
this.selectedDepartments= new ArrayList<>();
this.departmentList= new ArrayList<>();
this.departmentList = this.departmentDAO.listDepartments();
lazyModel = new StudentLazyList(StudentDAO){
#Override
public List<Student> load(int first, int pageSize, Map<String, SortMeta> sortBy, Map<String, FilterMeta> filterBy) {
return load2(first, pageSize, sortBy, filterBy,selectedDepartments);
}
};
}
}
Thanks for help.
The solution is found for those who encounter the same problem. it was relative to the converter, indeed I don't know why we have to use a converter when it comes to a Pojo class because we already mentioned the name of class in the value property of selectItems.
Nevermind , here is the code that works
The selectCheckboxMenu component
<h:form id="form1">
<p:selectCheckboxMenu id="menu" label="department" converter="departmentConverter" value="#{studentMB.selectedDepartments}"
multiple="true" filter="true" filterMatchMode="startsWith" style="width: 15rem" panelStyle="width: 15rem" scrollHeight="250" >
<c:selectItems value="#{studentMB.departmentList}" var="department" itemLabel="#{department.name}" itemValue="#{department}"/>
<p:ajax event="change" update=":form2:dt-students"/>
</p:selectCheckboxMenu>
</h:form>
The converter class
#Named
#FacesConverter(value = "departmentConverter")
public class DepartmentConverter implements Converter {
#Override
public Department getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null)
return null;
StudentMB data = context.getApplication().evaluateExpressionGet(context, "#{studentMB}", StudentMB.class);
int actualId=Integer.parseInt(value);
for(Department dep : data.getDepartmentList())
{
if(categ.getId()==actualId)
return dep;
}
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid department."));
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null) {
Department c=(Department)value;
return String.valueOf(c.getId());
}
else {
return null;
}
}
}
Hope this help

Retrieve class values from selectCheckboxMenu

I have a <p:selectCheckboxMenu> and I want to get the selected values back in bean. But the value I receive
when I select an item from the menu it's a string, representing the type field from the CategorizationBean.
I just want when I select an item from the table, to get the whole CategorizationBean structure in the bean.
This is the snippet from the xhtml page:
<p:selectCheckboxMenu label="Categorization"
value="#alertMB.selectedCategories}"
converter="com.converter.CategoryConverter">
<f:selectItems value="#{alertMB.categoryDomainEntry}"
var="category"
itemLabel="#{category.type}"
itemValue="#{category}"/>
</p:selectCheckboxMenu>
Snippet from bean:
public List<CategorizationBean> getSelectedCategories() {
return selectedCategories;
}
public void setSelectedCategories(List<CategorizationBean> selectedCategories) {
this.selectedCategories = selectedCategories;
}
public class CategorizationBean implements Serializable{
private String type;
private long id;
I think that you have missed by using a list of beans, I use this example and it works:
<p:selectCheckboxMenu id="slctRdBtn"
value="#{yourBean.compLovDtgrid}"
converter="compLovDtgridConverter">
<f:selectItems
value="#{yourBean.listCompLovDtgrid}"
var="rdbtn" itemLabel="#{rdbtn.vjlrLibelleRep}"
itemValue="#{rdbtn}" />
</p:selectCheckboxMenu>
and for the converter:
#FacesConverter(forClass=CompLovDtgrid.class , value="compLovDtgridConverter")
public class CompLovDtgridConverter implements Converter{
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
return (value instanceof CompLovDtgrid) ? ((CompLovDtgrid) value).getVjlrCodeRep() : null;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component,String value)
{
if(value == null)
return null;
YourBean data = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
for(CompLovDtgrid compLovDtgrid : data.getListCompLovDtgrid())
{
if(compLovDtgrid.getVjlrCodeRep().equals(value))
return compLovDtgrid;
}
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to CompLovDtgrid", value)));
}
}
and for the list, I use:
public List<CompLovDtgrid> getListCompLovDtgrid()
{
return listCompLovDtgrid;
}
public void setListCompLovDtgrid(List<CompLovDtgrid> listCompLovDtgrid) {
this.listCompLovDtgrid = listCompLovDtgrid;
}

Primefaces p:orderList java backing list does not update

I am currently implementing a orderable list using PrimeFaces' component, embedded inside a . I was able to get the list to appear properly with my items. However, when I saved the list and submitted it back to the server, the rearranged items did not get reflected in the backing bean for some reason. Since the Primefaces showcase was able to see the changes, what am I doing wrong?
XHTML Snippet:
<h:form id="confirmDialogForm">
<p:confirmDialog id="arrangeProjDialog" widgetVar="arrangeDlg" width="600"
header="Meeting Order"
appendToBody="true" message="Drag and drop to rearrange meeting order">
<p:orderList id="arrangeProjDialogList"
value="#{adminMeetingListBean.orderProjList}"
converter="#{adminMeetingListBean.rowConverter}"
var="po"
controlsLocation="left"
styleClass="wideList"
itemLabel="#{po.projectTitle}"
itemValue="#{po}"
>
<f:facet name="caption">Proposals</f:facet>
</p:orderList>
<p:commandButton value="Save" ajax="true" process="arrangeProjDialogList #this"
actionListener="#{adminMeetingListBean.updateProposalMeetingOrder}" onclick="arrangeDlg.hide();">
</p:commandButton>
<p:button value="Cancel" onclick="arrangeDlg.hide(); return false;" />
</p:confirmDialog>
</h:form>
Backing Bean:
public void updateProposalMeetingOrder() {
if (selectedMeeting != null) {
orderProjTitles.get(0);
meetingService.updateMeetingProjSequence(orderProjList, selectedMeeting.getMeetingId());
}
}
The List is a list of POJO "ProposalOrderRow" objects. This has the definition:
public class ProposalOrderRow implements Serializable {
private static final long serialVersionUID = -5012155654584965160L;
private int dispSeq;
private int appId;
private int assignmentId;
private String refNo;
private String projectTitle;
public int getDispSeq() {
return dispSeq;
}
public void setDispSeq(int dispSeq) {
this.dispSeq = dispSeq;
}
public int getAppId() {
return appId;
}
public void setAppId(int appId) {
this.appId = appId;
}
public String getRefNo() {
return refNo;
}
public void setRefNo(String refNo) {
this.refNo = refNo;
}
public String getProjectTitle() {
return projectTitle;
}
public void setProjectTitle(String projectTitle) {
this.projectTitle = projectTitle;
}
public int getAssignmentId() {
return assignmentId;
}
public void setAssignmentId(int assignmentId) {
this.assignmentId = assignmentId;
}
}
Converter:
#FacesConverter("proposalOrderRowConverter")
public class ProposalOrderRowConverter implements Converter {
private List<ProposalOrderRow> orderRows;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String newValue) {
if (newValue.isEmpty()) {
return null;
}
for (ProposalOrderRow item : orderRows) {
String refNo = item.getRefNo();
if (refNo.equals(newValue)) {
return item;
}
}
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
ProposalOrderRow row = (ProposalOrderRow) value;
String output = row.getRefNo();
return output;
}
public List<ProposalOrderRow> getOrderRows() {
return orderRows;
}
public void setOrderRows(List<ProposalOrderRow> orderRows) {
this.orderRows = orderRows;
}
}
This problem is caused by appendToBody="true" in the confirm dialog. Setting it to false solved the problem.
See link here: link

DataModel must implement org.primefaces.model.SelectableDataModel when selection is enabled.

I'm trying to create a DataTable with Multiple Row Selection but i'm getting an error here's the link of the tutorial http://www.primefaces.org/showcase/ui/datatableRowSelectionMultiple.jsf :
Here's my xhtml:
<p:dataTable border="1" value="#{projectAdminisrationMB.projectNoUsersList}"
var="userObj"
selection="#
{projectAdminisrationMB.selectedUsers}"
selectionMode="multiple" rowIndexVar="rowIndex"binding="#{table2}">
<p:column id="column3">
<f:facet name="header">
<h:outputText value=" user "></h:outputText>
</f:facet>
<h:outputText value="#{userObj.name}"/>
/
<h:outputText value="#{userObj.lastName}"></h:outputText>
<h:outputText value="#{userObj.firstName}"></h:outputText>
</p:column>
<f:facet name="footer">
<p:commandButton id="addProjectUser" value=" Add " onclick="dlg1.show()" />
<p:commandButton id="deleteProjectUser" value=" Delete " />
</f:facet>
</p:dataTable>
Managed Bean :
#ManagedBean
#SessionScoped
public class ProjectAdminisrationMB implements Serializable {
private static final long serialVersionUID = 1L;
private String projectName;
private List <User> projectUsersList;
private List<User> projectNoUsersList;
private List<User> selectedUsers;
private String projectAdmin;
public ProjectAdminisrationMB() {
super();
AdministrationProjectFinal administrationProjectFinal =new
AdministrationProjectFinal();
this.projectUsersList=administrationProjectFinal.getUserList();
this.projectNoUsersList=administrationProjectFinal.getNotUserList();
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public List<User> getProjectUsersList() {
return projectUsersList;
}
public void setProjectUsersList(List<User> projectUsersList) {
this.projectUsersList = projectUsersList;
}
public String getProjectAdmin() {
return projectAdmin;
}
public void setProjectAdmin(String projectAdmin) {
this.projectAdmin = projectAdmin;
}
public List<User> getProjectNoUsersList() {
return projectNoUsersList;
}
public void setProjectNoUsersList(List<User> projectNoUsersList) {
this.projectNoUsersList = projectNoUsersList;
}
public List<User> getSelectedUsers() {
return selectedUsers;
}
public void setSelectedUsers(List<User> selectedUsers) {
this.selectedUsers = selectedUsers;
}
}
i'm getting this error:
javax.faces.FacesException: DataModel must implement
org.primefaces.model.SelectableDataModel when selection is enabled.....
just add this attribute rowKey to the datatable tag :
<p:dataTable border="1" value="#{projectAdminisrationMB.projectNoUsersList}"
var="userObj"
rowKey="#{userObj.name}"selection="#{projectAdminisrationMB.selectedUsers}"
selectionMode="multiple" rowIndexVar="rowIndex"
binding="#{table2}">
You can get this error if you try to add a new item to the underlying list and forget to assign a value to that new item's rowKey.
Alternatively to rowKey you can wrap your data in a custom model which really implements org.primefaces.model.SelectableDataModel. This is helpful if
all of your your classes have the same kind of #Id (e.g. a long) and can implement the same interface (e.g. EjbWithId)
you want to add additional functionalities to your data which are not domain specific and don't belong e.g. User.
The interface may be something like this:
public interface EjbWithId
{
public long getId();
public void setId(long id);
}
Then a generic implementation of SelectableDataModel for all your classes can be used:
public class PrimefacesEjbIdDataModel <T extends EjbWithId>
extends ListDataModel<T> implements SelectableDataModel<T>
{
public PrimefacesEjbIdDataModel(List<T> data)
{
super(data);
}
#Override public T getRowData(String rowKey)
{
List<T> list = (List<T>) getWrappedData();
for(T ejb : list)
{
if(ejb.getId()==(new Integer(rowKey))){return ejb;}
}
return null;
}
#Override public Object getRowKey(T item) {return item.getId();}
}
In your #ManagedBean:
private PrimefacesEjbIdDataModel<User> dmUser; //+getter
dmUser = new PrimefacesEjbIdDataModel<User>(administrationProjectFinal.getUserList());
first check whether you've added
rowKey="#{userObj.id}"
then you need to have the data table List set in filteredValue attribute of your data table in xhtml, instead of value.

how can i call setter without calling <f:viewparam> converter?

i am using jsf 2.1.1 and primefaces 3.0.M4. i have a sample jsf page that used to post country comments. i use f:viewparam tag with converter to view country pages. here are the codes:
country.xhtml:
<f:metadata>
<f:viewParam name="country" value="#{countryBean2.selectedCountry}" converter="countryConverter" required="true"/>
</f:metadata>
<h:head>
<title>Country</title>
</h:head>
<h:body>
<h:form id="form">
<h:outputText value="#{countryBean2.selectedCountry.countryName}" />
<br/><br/>
<h:outputText value="Comment:" />
<h:inputText value="#{countryBean2.comment}" />
<br/>
<p:commandButton value="Send" action="#{countryBean2.sendComment}" update="#this" />
</h:form>
</h:body>
CountryBean2.java:
#Named("countryBean2")
#SessionScoped
public class CountryBean2 implements Serializable {
private EntityCountry selectedCountry;
private String comment;
public EntityCountry getSelectedCountry() { return selectedCountry; }
public void setSelectedCountry(EntityCountry newValue) { selectedCountry = newValue; }
public String getComment() { return comment; }
public void setComment(String newValue) { comment = newValue; }
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
public void sendComment() {
EntityManager em = emf.createEntityManager();
try {
FacesMessage msg = null;
EntityTransaction entr = em.getTransaction();
boolean committed = false;
entr.begin();
try {
EntityCountryComment c = new EntityCountryComment();
c.setCountry(selectedCountry);
c.setComment(comment);
em.persist(c);
committed = true;
msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("Comment was sended");
} finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
}
}
CountryConverter.java:
public class CountryConverter implements Converter {
public static EntityCountry country = new EntityCountry();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
#Override
public EntityCountry getAsObject(FacesContext context, UIComponent component, String value) {
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT c FROM EntityCountry c WHERE c.countryName = :countryName")
.setParameter("countryName", value);
country = (EntityCountry) query.getSingleResult();
return country;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
EntityCountry c = (EntityCountry) value;
return c.getCountryName();
}
}
i want to call "setComment" setter without calling CountryConverter, when i am using commandbutton to post comment. how can i do that ?
Unfortunately, that's by design of the <f:viewParam> component. It will convert the request parameter and set the property on every HTTP request, also on postbacks. In order to change this behaviour, you would need to extend <f:viewParam> with a custom component which doesn't remember the initial request parameter in its state. It's relatiely simple, instead of delegating the setSubmittedValue() and getSubmittedValue() to StateHelper, you just need to make it an instance variable. This is described in detail in this blog.
#FacesComponent("com.my.UIStatelessViewParameter")
public class UIStatelessViewParameter extends UIViewParameter {
private String submittedValue;
#Override
public void setSubmittedValue(Object submittedValue) {
this.submittedValue = (String) submittedValue;
}
#Override
public String getSubmittedValue() {
return submittedValue;
}
}
OmniFaces has an ready-to-use component for this in flavor of <o:viewParam>. Here is the live example.

Resources