Primefaces datatable filter issue with retaining object values when filter returns no rows - primefaces

I am using primefaces(6.2) datatable, while using column filter I am observing a weird behavior, though all the columns (with outputText, inputText) retain the object value, columns with 'selectOneMenu', 'selectBooleanCheckbox' not retaining the object value and returning null, false.
Issue occurring only while performing the filter and filer returns no rows, if the filter returns at least one row everything looks normal and all columns are behaving normally. please find below code snippet that I am using to troubleshoot, I really appreciate any inputs to resolve this issue.
XHTML
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jstl/core">
<h:body>
<h:form id="frmClientDetails">
<p:dataTable
value="#{myBean.lstContact}" var="varContact"
rowStyleClass="#{varContact.strRowCSS}">
<p:column width="180" headerText="Sal">
<p:selectOneMenu value="#{varContact.strSalutation}">
<f:selectItem itemLabel="--Select one--" itemValue=""></f:selectItem>
<f:selectItem itemLabel="DR" itemValue="DR"></f:selectItem>
<f:selectItem itemLabel="MISS" itemValue="MISS"></f:selectItem>
<f:selectItem itemLabel="MRS" itemValue="MRS"></f:selectItem>
<f:selectItem itemLabel="MR" itemValue="MR"></f:selectItem>
<f:selectItem itemLabel="MS" itemValue="MS"></f:selectItem>
</p:selectOneMenu>
</p:column>
<p:column width="200" filterBy="#{varContact.strFirstName}" headerText="First Name">
<p:inputText maxlength="2000" value="#{varContact.strFirstName}"/>
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
ManagedBean
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import org.springframework.context.annotation.Scope;
import com.model.Contact;
#Named("myBean")
#Scope("view")
public class MyBean extends BaseManagedBean {
private List<Contact> lstContact;
#PostConstruct
public void init() {
lstContact = new ArrayList<Contact>();
Contact obj1 = new Contact();
obj1.setStrSalutation("MR");
obj1.setStrFirstName("AAA");
Contact obj2 = new Contact();
obj2.setStrFirstName("BBB");
Contact obj3 = new Contact();
obj3.setStrSalutation("MR");
obj3.setStrFirstName("CCC");
lstContact.add(obj1);
lstContact.add(obj2);
lstContact.add(obj3);
}
public List<Contact> getLstContact() {
return lstContact;
}
public void setLstContact(List<Contact> lstContact) {
this.lstContact = lstContact;
}
}
If I just enter 'X' in second column(First Name) filter and remove 'X' all values at first column (Salutation) are gone.

Related

Strange bevavior of f:setPropertyActionListener inside ui:repeat and accordion

In a jsf/primefaces(version 6.2) project I have this peace of code to display a list of records in an accordion.
All the records are displayed correctly.
Inside a ui:repeat I have a p:commandButton to be able to save some text fragments (fragmt) using f:setPropertyActionListener.
I'm also implementing a second f:setPropertyActionListener to get an object (sRes). This one is working fine.
But the currentFrag variable get always populated with the text framgments from the last accordion.
<h:form id="accord" >
<p:accordionPanel value="#{myBean.lucSearchResults}" var="sRes" multiple="true">
<p:tab title="#{sRes.score}">
<ui:repeat value="#{sRes.frags}" var="fragmt">
<h:panelGrid columns="2" cellpadding="10">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText value="#{fragmt}" escape="false"/>
<hr/>
</h:panelGrid>
<h:panelGrid columns="1" cellpadding="10">
<p:commandButton action="#{myBean.saveFrag}" value="Save" >
<f:setPropertyActionListener value="#{sRes}" target="#{myBean.currentSearchResult}" />
<f:setPropertyActionListener value="#{fragmt}" target="#{myBean.currentFrag}" />
</p:commandButton>
</h:panelGrid>
</h:panelGrid>
</ui:repeat>
</p:tab>
</p:accordionPanel>
</h:form>
I have a long experience with JSF and Java. I have no explanation for this strange behavior.
Any help or pointer on this issue is much appreciated.
I can reproduce this using Primefaces 7.0, Mojarra 2.3.3, JVM 1.8.0_152-b16, Apache Tomcat 9.0.21, Openwebbeans 2.0.7 using this example:
<h:form id="frm">
<p:accordionPanel id="accordion" value="#{myBean.cats}" var="cat"
multiple="true">
<p:tab id="tab" title="#{cat.name}">
<ui:repeat var="kid" value="#{cat.kitten}">
<h:panelGroup id="group">
<p:commandButton id="cmdSubmit" action="#{myBean.doSomething()}"
value="submit #{cat.name} - #{kid.name} " process="#form"
update=":frm:output">
<f:setPropertyActionListener value="#{cat}"
target="#{myBean.cat}" />
<f:setPropertyActionListener value="#{kid}"
target="#{myBean.kid}" />
</p:commandButton>
</h:panelGroup>
</ui:repeat>
</p:tab>
</p:accordionPanel>
<h:outputText id="output"
value="#{myBean.cat.name} - #{myBean.kid.name}" />
</h:form>
This is my bean:
package my.package;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 43L;
private List<Cat> cats;
private Cat cat;
private Cat kid;
#PostConstruct
public void init() {
cats = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final Cat cat = new Cat();
cats.add(cat);
cat.setName(String.valueOf(i));
cat.setKitten(new ArrayList<>());
for (int j = 0; j < 5; j++) {
final Cat kid = new Cat();
kid.setName(i + "." + j);
cat.getKitten().add(kid);
}
}
}
public void doSomething() {
System.err.println(cat.getName() + " / " + kid.getName());
}
// getters & setters ...
public static class Cat {
private String name;
private List<Cat> kitten;
// getters & setters ...
}
}
When hitting e.g. the command button reading "5 - 5.4" the output is "5 - 9.4":
When replacing p:accordion/p:tab with ui:repeat, this example works as expected. This suggests it has something todo with primefaces dynamic tabs and might be worth a bug report.
When replacing process="#form" with process="#this" or process="group" it also works as expected and outputs the correct label of the button pressed.
An even better work around for this is to use the p:repeat component implemented to solve known incompatibilities between tabView/accordion/dataTable and different ui:repeat implementations.

Primefaces selectCheckboxMenu erratic behavior when deselecting individual checkboxes

In an application based on jsf 2.1 and Primefaces 6.1.5, I have difficulties implementing a <p:selectCheckboxMenu
I simplified the code according to the instructions here How to create a Minimal, Complete, and Verifiable example
My code now looks quite similar to the code in the Primefaces Showcase.
Primefaces Showcase
After much analyzing, I can describe 'erratic' a bit better. When deselecting an item, the item following it is affected. The last item is not affected at all. And the first item can never be deselected. It seems like a bug in the use of indices.
Can anyone confirm this and perhaps suggest a Workaround?
Here is the xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:form id="form">
<p:panel>
<p:selectCheckboxMenu id="testSCM"
value="#{myForm.testList}"
multiple="true"
label="Choose item..."
updateLabel="true">
<f:selectItems var="s" value="#{myForm.testItems}" itemLabel="#{s}" />
</p:selectCheckboxMenu>
</p:panel>
<p:commandButton value="Submit" update="displayItems" oncomplete="PF('itemDialog').show()" style="margin-top:10px;" />
<p:dialog header="Selected Items" modal="true" showEffect="fade" hideEffect="fade" widgetVar="itemDialog" width="250">
<p:outputPanel id="displayItems">
<p:dataList value="#{myForm.statusList}" var="item" emptyMessage="No items selected">
<f:facet name="header">
Status
</f:facet>
#{item}
</p:dataList>
</p:outputPanel>
</p:dialog>
</h:form>
</ui:composition>
And this is the form:
#Named("myForm")
#SessionScoped
public class MyForm implements Serializable {
private String[] testList;
private List<String> testItems;
public String[] getTestList() {
return testList;
}
public void setTestList(String[] testList) {
this.testList = testList;
}
public List<String> getTestItems() {
return testItems;
}
public void setTestItems(List<String> testItems) {
this.testItems = testItems;
}
public void reset() {
testItems = new ArrayList<>();
testItems.add("Item1");
testItems.add("Item2");
testItems.add("Item3");
testItems.add("Item4");
testItems.add("Item5");
testItems.add("Item6");
}
}
The problem was caused by a bug in Primefaces version 6.1.5. The code works fine when downgrading to Version 6.0 or upgrading to Version 6.1.8, which is what I chose to do.
The problem is described in Primefaces issue tracker on github

p:datatable: How to edit data in a p:dialog?

Context
I have a datatable with a button that opens a dialog when clicked. That dialog shows additional data (xml content) in a p:inputTextarea
Question
Now I would like to make this p:inputTextarea editable and have the changes reflected in the object of the datatable. I wanted to add a commandbutton in the dialog to save the changes. How do I get a reference to the selected object ?
Xhtml
<h:form id="alltxform">
<p:dataTable id="tablealltx" var="transaction" value="#{transactionListModel.txList}">
<p:column>
<p:commandButton update=":alltxform:xmlDetail" oncomplete="PF('dialog').show()">
<f:setPropertyActionListener value="#{transaction}"
target="#{transactionListModel.selectedTx}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:dialog header="Detail" widgetVar="dialog">
<p:outputPanel id="xmlDetail">
<p:inputTextarea readonly="false" id="xmlviewer"
value="#{transactionListModel.selectedTx.xml}" />
</p:outputPanel>
</p:dialog>
</h:form>
Model
package model;
#Named
#SessionScoped
public class TransactionListModel implements Serializable {
private static final long serialVersionUID = 1L;
private List<TransactionVO> txList;
private TransactionVO selectedTx;
public TransactionVO getSelectedTx() {
return selectedTx;
}
public void setSelectedTx(TransactionVO selectedTx) {
this.selectedTx = selectedTx;
}
#PostConstruct
public void init() {
txList = new ArrayList<TransactionVO>();
}
public List<TransactionVO> getTxList() {
return txList;
}
public void clearList(){
txList = new ArrayList<TransactionVO>();
}
}
Button
I want to add this button to the dialog.
<p:commandButton value="OK" onclick="PF('dialog').hide();" actionListener=""/>
I read about cellEdit events, but that's not really what I need. I need a reference to my transaction object inside the dialog in order to save the changes.
Do you mean the dialog will look like -
<p:dialog header="Detail" widgetVar="dialog">
<p:outputPanel id="xmlDetail">
<p:inputTextarea readonly="false" id="xmlviewer"
value="#{transactionListModel.selectedTx.xml}" />
<p:commandButton value="OK" onclick="PF('dialog').hide();" actionListener=""/>
</p:outputPanel>
</p:dialog>
And the action will refresh the model, before refreshing the table?
And you want to access TransactionListModel.selectedTx?
Well if its in the model and accessible from the controller then just -
actionListener="#{yourController.yourAction(transactionListModel.selectedTx)}"
And Update the underlying datastructure in the yourAction method, before updating :tablealltx:tablealltx

Primefaces datatable filter doesn't work

I must do something fundamentally wrong, I stripped down the code to the bare minimum with a data table and enabling one column filter and a globe filter.
The funny thing is that the example code from Primefaces works. The only difference to my code should be that it gathers data from a DB rather than generating it in the bean.
I have no more clues why my example doesn't do anything when I type something in the filter would be appreciate any ideas here.
My xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="layout.xhtml">
<ui:define name="title">All Projects</ui:define>
<ui:define name="content">
<p:dataTable var="project" value="#{projectController.allProjects}" widgetVar="projectTable" filteredValue="#{projectController.filteredProjects}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="PF('projectTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column headerText="Name" filterBy="#{project.name}">
<h:outputText value="#{project.name}" />
</p:column>
<p:column headerText="Priority">
<h:outputText value="#{project.priority}" />
</p:column>
<p:column headerText="Exit">
<h:outputText value="#{project.exitCriteria}" />
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
My Bean:
package com.apa.projectd.common;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.inject.Inject;
import com.habony.common.Loggable;
import com.habony.projectd.ejbs.ProjectEJB;
import com.habony.projectd.enteties.Project;
#ManagedBean(name="projectController")
#SessionScoped
#Loggable
public class ProjectController implements Serializable{
private static final long serialVersionUID = 8345760187637787728L;
#Inject
private ProjectEJB projectEJB;
private List<Project> filteredProjects;
private List<Project> allProjects;
#PostConstruct
public void loadAllProjects(){
allProjects = projectEJB.getAllProjects();
}
//
// Getters and Setters
//
public List<Project> getFilteredProjects() {
return filteredProjects;
}
public void setFilteredProjects(List<Project> filteredProjects) {
this.filteredProjects = filteredProjects;
}
public void setAllProjects(List<Project> allProjects) {
this.allProjects = allProjects;
}
public List<Project> getAllProjects(){
return allProjects;
}
}
The filters features of p:dataTable need to be wrapped in <h:form> tags for work fine. The code xhtml modified would:
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="layout.xhtml">
<ui:define name="title">All Projects</ui:define>
<ui:define name="content">
<h:form>
<p:dataTable var="project" value="#{projectController.allProjects}" widgetVar="projectTable" filteredValue="#{projectController.filteredProjects}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="PF('projectTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column headerText="Name" filterBy="#{project.name}">
<h:outputText value="#{project.name}" />
</p:column>
<p:column headerText="Priority">
<h:outputText value="#{project.priority}" />
</p:column>
<p:column headerText="Exit">
<h:outputText value="#{project.exitCriteria}" />
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
Please see lazy property this may be that your data not filter.
lazy="true" change lazy=false
finally I figured out that when you use Lazy the filtered data is not stored in other variable as in non lazy implementation, everytime you call a filter the load method is executed, so I had to put the filters also in my Load, also the sorting this is the way when using Lazy.
My mistake !
You should initialize filtredProjects with the same data that contains the ArrayList allProjects like this:
#PostConstruct
public void loadAllProjects(){
allProjects = projectEJB.getAllProjects();
filtredProjects = projectEJB.getAllProjects();
}
Do not use lazy loading when filtering and/or sorting

PrimeFaces commandButton is not working

I know this is a very common issue which happens for a variety of reasons, but although I have searched about it a lot, I didn't manage to find a solution for my case.
My primefaces commandButton is inside an h:form and is declared as follows:
<p:commandButton action="#{userGroupBean.createOrUpdateItemAction}"
value="#{userGroupBean.actionCreateOrUpdateLabel}"
icon="iconDisk"
update="#form"
oncomplete="window.scrollTo(0,0);" />
My UserGroupBean is ViewScoped.
This button when clicked is supposed to create a userGroup and show a "Successful creation" message. Instead of doing this it just shows "Please wait" loader for a second and then does nothing. There are no errors in the log and through remote debugging I confirmed that it doesn't enter the action method.
The weird thing is that when I run the same code in a local Tomcat installation it runs successfully. Also, on the remote server this application is deployed, this used to work just fine. All happened suddenly, and I have a lot of commandButtons like this one, across my application which still work great. Something seems to go wrong just with this particular page .
I use PrimeFaces 3.1 version, I dont know what other information is usefull to provide.
Any help/ideas is/are appreciated.
EDIT
This is userGroup.xhtml (the page whose buttons do not work) code:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:comps="http://java.sun.com/jsf/composite/components"
template="/WEB-INF/templates/userGroup/edit.xhtml">
<f:metadata>
<f:event type="preRenderView" listener="#{userGroupBean.initUserGroupUsersList}" />
</f:metadata>
<ui:define name="title">
User Group
</ui:define>
<ui:define name="centerUnit">
<h:form>
<h:panelGrid columns="3" styleClass="ui-messages-info ui-corner-all" rendered="#{not empty flash.messages_info}">
<span class="ui-message-info-icon"></span>
#{flash.messages_info}
</h:panelGrid>
<p:messages showDetail="true" globalOnly="true" />
<p:panel header="Settings">
<h:panelGrid columns="3" cellpadding="5">
<h:outputLabel for="title" value="User Group Title:" />
<p:inputText id="title" value="#{userGroupBean.userGroup.title}" />
<p:message for="title" />
</h:panelGrid>
</p:panel>
<p:panel header="Members">
<p:pickList value="#{userGroupBean.usersGroupUsersList}" var="user"
iconOnly="true"
converter="userConverter"
itemLabel="#{user.username}" itemValue="#{user}">
<f:facet name="sourceCaption">Available</f:facet>
<f:facet name="targetCaption">Participating</f:facet>
<p:column style="width:25%">
<p:graphicImage value="#{facesContext.externalContext.request.contextPath}/../file?thumbnail=&downloadPath=#{user.contactDetails.picture.downloadPath}" width="40" height="40" />
</p:column>
<p:column style="width:25%">
<h:outputText value="#{user.username}" />
</p:column>
<p:column style="width: 50%">
<h:outputText value="#{user.contactDetails.lastName} #{user.contactDetails.firstName}"/>
</p:column>
</p:pickList>
</p:panel>
<p:commandButton
action="#{userGroupBean.createOrUpdateItemAction}"
value="#{userGroupBean.actionCreateOrUpdateLabel}"
icon="iconDisk"
update="#form"
oncomplete="window.scrollTo(0,0);" />
<p:separator />
<p:outputPanel style="text-align:right" layout="block" rendered="#{!userGroupBean.userGroup.isNew() and userGroupBean.hasUserModifyUserGroupAuthority()}">
<h:panelGroup>
<p:commandButton value="Delete" title="Do you want to delete this user group?"
action="#{userGroupBean.deleteItemAction}"
update="#form"
icon="iconDelete" />
<p:commandButton value="Leave user group" title="I want to leave this user group"
action="#{userGroupBean.userInSessionLeavesUserGroupAction}"
update="#form"
icon="iconUserGo"/>
</h:panelGroup>
</p:outputPanel>
</h:form>
</ui:define>
The UserGroupBean.java:
#Controller("userGroupBean")
#Scope(value = "view")
public class UserGroupBean extends GenericBean<UserGroup> {
private static final long serialVersionUID = 1L;
final Log logger = LogFactory.getLog(getClass());
#Autowired
private SessionServiceImpl sessionService;
#Autowired
protected UserGroupService userGroupService;
#Autowired
protected UserService userService;
#Override
public String getPageCreateOrUpdate() { return "userGroup.xhtml"; }
#Override
public String getPageList() { return "../../my/userGroups.xhtml"; }
/** Wrapper method which calls getItem() */
public UserGroup getUserGroup() { return getItem(); }
/** Wrapper method which calls setItem() */
public void setUserGroup(UserGroup UserGroup) { setItem(UserGroup); }
protected UserGroup findItemById(Integer userGroupId) {
return userGroupService.findUserGroupById(userGroupId);
}
#Override
protected void resolveCreateRequest(HttpServletRequest req) {
logger.debug("UserGroupBean::resolveCreateRequest()");
setItem( userGroupService.initializeUserGroup("") );
}
#Override
protected String createItem() {
try {
if(!isValidUsersSelection(new ArrayList<User>(usersGroupUsersList.getTarget())))
return null;
List<Integer> userIds = new ArrayList<Integer>();
for(User user: usersGroupUsersList.getTarget())
userIds.add(user.getId());
userGroupService.saveUserGroup(getUserGroup(), userIds);
helperFacesContext.addInfoMessageToFlash("User Group successfully created.");
return getPageCreateOrUpdate()+"?action=update&id="+getItem().getId()+"&faces-redirect=true";
}
catch (Exception e) {
JsfUtils.error("There was an error", e.getMessage());
return null;
}
}
.....
}
And finally the UservConverter.java
#FacesConverter(value = "userConverter")
public class UserConverter extends GenericConverter {
final Log logger = LogFactory.getLog(getClass());
private UserDAO getUserDAO(FacesContext facesContext) {
// #Autowired gives null
return (UserDAO) FacesContextUtils.getWebApplicationContext(facesContext).getBean("userDAO");
}
/**
* converts the String representation of the key back to the Object
*/
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) throws ConverterException {
logger.info("UserConverter::getAsObject("+value+")");
Integer userId = Integer.valueOf(value);
try {
return getUserDAO(context).findById(userId);
} catch(Exception e) {
throw new ConverterException(handleException(context,e.getMessage()));
}
}
NEW CLUE: When I restart the server and only after that, when I access this page and manage to create a user group before userGroup.xhtml is fully loaded, the user group is created just fine. If I restart the server and wait till the page is loaded and then create a user group again nothing happens. This problem will drive me crazy at the end.