Primefaces RowEditor not changing value in Datatable - jsf

I'm using a datatable with a roweditor, my code is more or less the same as the code on the showcase example on the primefaces website but for some reason, the values are not updated.
Also when I click on the pencil to edit, the current value is not showing up in the editing cell.
Here's my code:
xhtml:
<h:form id="updateform">
<p:dataTable id="updatetable" value="#{EditingBean.row}" var="column"
editable="true"
style="width: 780px; overflow-x: auto; white-space: normal;">
<f:facet name="header">TEST</f:facet>
<p:column rendered="#{column.display}" style="white-space: normal;">
<h:outputText value="#{column.alias}" />
</p:column>
<p:column rendered="#{column.display}" style="white-space: normal;">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{column.value}" />
</f:facet>
<f:facet name="input">
<p:inputText value="{#column.value}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column rendered="#{column.display}" style="white-space: normal;">
<p:rowEditor rendered="#{column.modify}" />
</p:column>
</p:dataTable>
</h:form>
EditingBean:
#ManagedBean(name = "EditingBean")
#ViewScoped
public class EditingBean implements Serializable {
private static final long serialVersionUID = -772702647887310138L;
private List<Result> row;
public List<Result> getRow() {
return row;
}
public void setRow(List<Result> row) {
this.row = row;
}
}
Result:
public class Result implements Serializable {
private static final long serialVersionUID = 1L;
private String alias;
private String name;
private String value;
private String modify;
private String display;
// getters + setters

You have a typo in the code, change {#column.value} to #{column.value}.

Related

Edit row in PrimeFaces dataTable does not update object

With a PrimeFaces dataTable I try to edit a row. But when I click on the 'Save Row' button, the old value is send to the bean.
I tried to copy the database object to a normal pojo, but still the old value is send to the bean.
I use PrimeFaces 12
XHTML:
<h:form id="form">
<p:growl id="msgs" showDetail="true"/>
<div class="container-fluid">
<h1><h:outputText value="#{txt['rider.title']}"/></h1>
<p:dataTable id="dt_riders" class="table table-striped" value="#{riderView.allRiders}"
var="rider" editable="true">
<p:ajax event="rowEdit" listener="#{riderView.onRowEdit}" update=":form:msgs"/>
<p:ajax event="rowEditCancel" listener="#{riderView.onRowCancel}" update=":form:msgs"/>
<p:column headerText="#{txt['rider.header.id']}">
<h:outputText value="#{rider.id}"/>
</p:column>
<p:column headerText="#{txt['rider.header.name']}">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{rider.name}"/>
</f:facet>
<f:facet name="input">
<p:inputText id="nameInp" value="#{rider.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<!-- and a few more -->
<p:column>
<p:rowEditor editTitle="Edit Row" cancelTitle="Cancel Edit" saveTitle="Save Row"/>
</p:column>
</p:dataTable>
</div>
</h:form>
The bean:
#ViewScoped
#Named("riderView")
public class RiderView implements Serializable {
private final RiderEjb riderEjb;
private final SecurityOfficer securityOfficer;
public RiderView() {
this(null, null);
}
#Inject
public RiderView(RiderEjb riderEjb, SecurityOfficer securityOfficer) {
this.riderEjb = riderEjb;
this.securityOfficer = securityOfficer;
}
public List<Rider> getAllRiders() {
return riderEjb.findAll(securityOfficer.getTeam());
}
public void onRowEdit(RowEditEvent<Rider> event) {
FacesMessage msg = new FacesMessage("Rider Edited", String.valueOf(event.getObject().getName()));
FacesContext.getCurrentInstance().addMessage(null, msg);
riderEjb.addOrUpdate(event.getObject());
}
public void onRowCancel(RowEditEvent<Rider> event) {
FacesMessage msg = new FacesMessage("Edit Cancelled", String.valueOf(event.getObject().getName()));
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
The Java object (getters and setters are generated by Lombok):
#Entity
#Getter
#Setter
public class Rider extends AbstractEntity {
#Id
private Long id;
private String name;
private Double weight;
private String gpxNames;
}
The problem was the method getAllRiders(). That calls the bean to gather the riders from the database. I changed it to retrieve all those riders from the database in a new #PostConstruct init() method.
Thanks to Jasper de Vries, I used the primefaces-test to pinpoint the problem.

Problems after using Primefaces filter

I have a datatable where one of the columns is editable.
As long as i dont use my filter i can navigate through my list and can edit the entry in any row i want. I dont get any errors and my changes are persisted in the DB correctly.
But after i once used any of the filter everything goes sideways. The filter itself works properly.
But when i now try to edit any entry the event.oldValue() from my CellEditEvent is always null and i cant persist my entries.
And only the first page of my paginator is filled with data. Every other page is empty.
Here is the view:
<div class="Container100">
<p:dataTable paginator="true" rows="15" var="listReportingParticipantOverview" value="#{reportingBean.listReportingParticipantOverview}"
id="participantOverviewId" widgetVar="participantOverviewId"
editable="true" editMode="cell" editInitEvent="dblclick"
emptyMessage="#{msg['system.no_result']}"
filteredValue="#{reportingBean.filteredListReportingParticipantOverview}">
<p:ajax event="cellEdit" listener="#{reportingBean.onCellEdit}" update=":reportingForm:msgs"/>
<p:column headerText="#{msg['model.reporting.participant_overview.name']}" filterBy="#{listReportingParticipantOverview.name}" filterMatchMode="contains">
<h:outputText value="#{listReportingParticipantOverview.name}" />
</p:column>
<p:column headerText="#{msg['model.reporting.participant_overview.dateOfBirth']}" filterBy="#{listReportingParticipantOverview.dateOfBirth}" filterMatchMode="contains">
<h:outputText value="#{listReportingParticipantOverview.dateOfBirth}" />
</p:column>
<p:column headerText="#{msg['model.reporting.participant_overview.email']}" filterBy="#{listReportingParticipantOverview.email}" filterMatchMode="contains">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{listReportingParticipantOverview.email}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{listReportingParticipantOverview.email}" style="width:100%" label="name"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</div>
Here is the bean:
#SessionScoped
#ManagedBean(name = "reportingBean2")
public class ReportingBean2 extends BeanController implements Serializable {
List<ReportingParticipantOverview> listReportingParticipantOverview = new ArrayList<ReportingParticipantOverview>();
List<ReportingParticipantOverview> filteredListReportingParticipantOverview;
ContactRepository contactRepository;
ContactRepository contactRepositoryOtherDBContext;
CommunicationRepository communicationRepositoryOtherDBContext;
private AbstractApplicationContext otherDBContext;
public void initData() {
this.listReportingParticipantOverview = this.contactRepositoryOtherDBContext
.selectParticipantOverviewReporting();
}
#PostConstruct
public void init() {
otherDBContext = new ClassPathXmlApplicationContext("applicationContext_otherDB.xml");
this.contactRepository = this.getApplicationContext().getBean(ContactRepository.class);
this.contactRepositoryOtherDBContext = otherDBContext.getBean(ContactRepository.class);
this.communicationRepositoryOtherDBContext = otherDBContext.getBean(CommunicationRepository.class);
}
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
public List<ReportingParticipantOverview> getListReportingParticipantOverview() {
return listReportingParticipantOverview;
}
public void setListReportingParticipantOverview(
List<ReportingParticipantOverview> listReportingParticipantOverview) {
this.listReportingParticipantOverview = listReportingParticipantOverview;
}
public List<ReportingParticipantOverview> getFilteredListReportingParticipantOverview() {
return filteredListReportingParticipantOverview;
}
public void setFilteredListReportingParticipantOverview(
List<ReportingParticipantOverview> filteredListReportingParticipantOverview) {
this.filteredListReportingParticipantOverview = filteredListReportingParticipantOverview;
}
}
}
I am using Java 8, Eclipse 2021-03 and Primefaces 10.0.0.
Any help appreciated :-)

Updating row on complete of <p:ajax event="cellEdit">

I want to update cellValue in same row.
I followed the sugestions of BalusC
Updating entire <p:dataTable> on complete of <p:ajax event="cellEdit">
After all my code perform 2 Requests. The secound one makes a full page Reload and all data will reseted.
I also tried <p:remoteCommand name="updateTable" process="#this" update="kAbnrTbl" /> following this suggestion.
Using a p:remoteCommand to update a p:dataTable
Here is JSF Page:
<h:form id="kalkEditForm">
<p:outputPanel id="dropArea">
<p:remoteCommand name="updateTable" update="kAbnrTbl" />
<p:dataTable id="kAbnrTbl" value="#{tableBean.data}" var="data" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="updateTable()"/>
<p:column headerText="Col1">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{data.col1}" /></f:facet>
<f:facet name="input"><p:inputText value="#{data.col1}" /></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Col2">
<h:outputText value="#{data.col2}" />
</p:column>
</p:dataTable>
</p:outputPanel>
</h:form>
And here Bean:
#ManagedBean(name="tableBean")
#ViewScoped
public class TableBean {
public TableBean() {
RowData entry = new RowData("a1", "b1");
entries.add(entry);
entry = new RowData("a2", "b2");
entries.add(entry);
entry = new RowData("a3", "b3");
entries.add(entry);
}
public class RowData {
private String col1;
private String col2;
public RowData(String col1, String col2) {
this.col1 = col1;
this.col2 = col2;
}
public String getCol1() {
return col1;
}
public void setCol1(String col1) {
this.col1 = col1;
}
public String getCol2() {
return col2;
}
public void setCol2(String col2) {
this.col2 = col2;
}
}
private final ArrayList<RowData> entries = new ArrayList<RowData>();
public List<RowData> getData() {
return entries;
}
public void onCellEdit(CellEditEvent event) {
final DataTable dataTable = (DataTable)event.getComponent();
RowData data = (RowData) dataTable.getRowData();
data.setCol2("changed");
}
}
I have no idea what is wrong with the code. Why perform <p:remoteCommand ... the second Request.
Using:Primface 5.3
Back to the beginning point. If I don't use <p:remoteCommand name="updateTable" update="kAbnrTbl" /> hack, it works ok but I have to press the refreshButton.
If I use the hack I have 2 Requests and a full page reload. There must be a tiny typo or something that I overlook.
Here the code without the hack.
<h:form id="kalkEditForm">
<p:outputPanel id="dropArea">
<!-- <p:remoteCommand name="updateTable" update="kAbnrTbl" /> -->
<p:dataTable id="kAbnrTbl" value="#{tableBean.data}" var="data" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update="kAbnrTbl"/>
<!-- <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="updateTable()"/> -->
<p:column headerText="Col1">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{data.col1}" /></f:facet>
<f:facet name="input"><p:inputText value="#{data.col1}" /></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Col2">
<h:outputText value="#{data.col2}" />
</p:column>
</p:dataTable>
</p:outputPanel>
<p:commandButton id="refreshButton" value="Redisplay" update="kAbnrTbl" />
</h:form>
I used event="rowEdit", this worked for me.
<p:ajax event="rowEdit" listener="#{tableBean.onCellEdit}" oncomplete="updateTable()" />
Following the note from user3821232, the workaround is to be used instead of "celleditor" "inplace" in conjunction with a standard <p:ajax.. call.
Here you can see the workaround.
xthml:
<h:form id="kalkEditForm">
<p:outputPanel id="dropArea">
<p:dataTable id="kAbnrTbl" value="#{tableBean.data}" var="data" editable="true" editMode="cell" rowIndexVar="row">
<p:column headerText="Col1" id="col1" sortBy="#{data.col1}" sortable="true">
<p:inplace>
<f:facet name="output"><h:outputText value="#{data.col1}" /></f:facet>
<f:facet name="input">
<p:inputText value="#{data.col1}" >
<p:ajax event="blur" process="#this" listener="#{tableBean.updateData(row, 'col1')}" update="kAbnrTbl"/>
</p:inputText>
</f:facet>
</p:inplace>
</p:column>
<p:column headerText="Col2">
<h:outputText id="col2" value="#{data.col2}" />
</p:column>
</p:dataTable>
</p:outputPanel>
</h:form>
Bean:
#ManagedBean(name="tableBean")
#ViewScoped
public class TableBean {
private static final Logger logger = Logger.getLogger(TableBean.class);
public TableBean() {
RowData entry = new RowData("a1", "b1");
entries.add(entry);
entry = new RowData("a2", "b2");
entries.add(entry);
entry = new RowData("a3", "b3");
entries.add(entry);
}
public class RowData {
private String col1;
private String col2;
public RowData(String col1, String col2) {
this.col1 = col1;
this.col2 = col2;
}
public String getCol1() {
return col1;
}
public void setCol1(String col1) {
this.col1 = col1;
}
public String getCol2() {
return col2;
}
public void setCol2(String col2) {
this.col2 = col2;
}
}
private final ArrayList<RowData> entries = new ArrayList<RowData>();
public List<RowData> getData() {
return entries;
}
public void updateData(Integer row, String colName){
logger.debug(String.format("updateData called row:%d colName %s", row, colName));
RowData data = getData().get(row);
data.setCol2("changed");
}
}

JSF Primefaces datatable doesn't show the right values

I have a problem with primefaces datatable. I'm getting the data from my database and it's saved in a list. That's works great! But the datatable just displays one column instead of four and this column is copied in every row.
<h:form id="userslistform">
<p:dataTable id="userlist" var="users" value="#{userBean.usersList}"
rowKey="#{userBean.username}">
<p:column headerText="ID">
<h:outputText value="#{userBean.id}" />
</p:column>
<p:column headerText="Username">
<h:outputText value="#{userBean.username}" />
</p:column>
<p:column headerText="Firstname">
<h:outputText value="#{userBean.firstname}" />
</p:column>
<p:column headerText="Surname">
<h:outputText value="#{userBean.surname}" />
</p:column>
</p:dataTable>
</h:form>
Bean:
#Named
#SessionScoped
#ManagedBean(name = "userBean")
public class UserBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String password;
private String firstname;
private String surname;
private Long id;
private String email;
private Long treeId;
private Boolean isadmin;
private List<User> usersList;
private User selectedUser;
private UserDataQuery query = new UserDataQuery();
//getter and setters of every attribute
...
#PostConstruct
public void init() {
usersList = query.getAllUsers();
}
}
DAO:
public class UserDataQuery {
private EntityManagerFactory enf;
private EntityManager em;
public UserDataQuery() {
enf = Persistence.createEntityManagerFactory("xxxx");
em = enf.createEntityManager();
em.getTransaction().begin();
}
public List<User> getAllUsers() {
List<User> usersList = em.createNamedQuery("User.findAll", User.class)
.getResultList();
return usersList;
}
...
}
You need to use value from var inside your table, to display the data
<h:form id="userslistform">
<p:dataTable id="userlist" var="users" value="#{userBean.usersList}"
rowKey="#{userBean.username}">
<p:column headerText="ID">
<h:outputText value="#{users.id}" />
</p:column>
<p:column headerText="Username">
<h:outputText value="#{users.username}" />
</p:column>
<p:column headerText="Firstname">
<h:outputText value="#{users.firstname}" />
</p:column>
<p:column headerText="Surname">
<h:outputText value="#{users.surname}" />
</p:column>
</p:dataTable>
</h:form>
var value represents a reference to current row, at the time the table is rendered. With #{userBean.<attribute>} you were always displaying values that were fixed. And, now you don't need those attributes in the bean itself, just the list (unless, of course, you need them for another purpose).

Display a summation of a data table column on the footer of the column

For example,
<p:dataTable var="price" value="#{testManagedBean.price}" rowIndexVar="rowIndex">
<p:column headerText="Index">
<h:outputText value="#{rowIndex+1}"/>
</p:column>
<p:column headerText="Price" style="text-align: right;">
<h:outputText value="#{price}"/>
<f:facet name="footer">
<c:set var="total" value="${total+price}"/>
<h:outputText value="#{total}"/>
</f:facet>
</p:column>
</p:dataTable>
The managed bean:
#ManagedBean
#ViewScoped
public final class TestManagedBean implements Serializable
{
private List<BigDecimal>price;
private static final long serialVersionUID = 1L;
#PostConstruct
public void init()
{
price=new ArrayList<>();
price.add(new BigDecimal(50));
price.add(new BigDecimal(100));
price.add(new BigDecimal(150));
price.add(new BigDecimal(200));
price.add(new BigDecimal(250));
price.add(new BigDecimal(300));
}
public List<BigDecimal> getPrice() {
return price;
}
}
The total of list of items is to be displayed on the footer.
Is this possible to do this summation using JSTL or otherwise without having a method that does this summation in the backing bean itself?
Currently the operation with JSTL <c:set> yields 0 on the footer of the associated column.
Something like this works for me:
<c:set var="total" value="0"/>
<c:forEach items="#{testManagedBean.price}" var="t">
<c:set var="total" value="#{total + t}"/>
</c:forEach>
<h:outputText value="#{total}"/>
I will not reject the idea it might be optimizable :-)

Resources