Reputation: 438
DataTable
does refresh, but not rendering list correctly. (JSF 2.2, Mojarra 2.2.0, PrimeFaces 5.2)
I have a list of dates in a PrimeFaces DataTable
that I'm reordering each time the user adds or edits the date. This almost works perfectly. Please help me see what I'm doing wrong, or let me know I've found a bug. (Note, its not the update
target, since I tried using update="@all"
which didn't change anything.)
Try this with my code below:
1) Add 11/21/2015 then add 11/20/2015. Notice it reordered them onAdd
.
Console:
onAdd, after
DataTableEntry[Date:Fri Nov 20 00:00:00 EST 2015]
DataTableEntry[Date:Sat Nov 21 00:00:00 EST 2015]
2) Then edit 11/21/2015 changing it to 11/19/2015. Notice the edited one went away and now there's two 20's. Bug?!?
Console:
onRowEdit, before
DataTableEntry[Date:Fri Nov 20 00:00:00 EST 2015]
DataTableEntry[Date:Thu Nov 19 00:00:00 EST 2015]
onRowEdit, after
DataTableEntry[Date:Thu Nov 19 00:00:00 EST 2015]
DataTableEntry[Date:Fri Nov 20 00:00:00 EST 2015]
3) Then hit my "Refresh page" commandButton. It now displays correctly.
Adding dates never has a problem regardless of its before/between/after positions. I found that you can edit the date, and as long as it doesn't actually change the order, it works fine. The moment the order is changed, the edited one disappears and one next to it gets visually duplicated into its place.
datatablesort.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
<title><ui:insert name="title">DataTable</ui:insert></title>
</h:head>
<h:body>
<h:form id="modelerForm">
<p:commandButton value="Refresh page" ajax="false"/>
<h:outputLabel for="date" value="Date"/>
<h:panelGroup>
<p:calendar id="date" pattern="MM/dd/yyyy" placeholder="mm/dd/yyyy" mask="true" showOn="button" navigator="true"/>
<h:commandButton value="Add">
<f:ajax event="action" listener="#{dataTableBean.onAdd}" execute="date" render="entries"/>
</h:commandButton>
</h:panelGroup>
<p:dataTable id="entries" value="#{dataTableBean.entries}" var="entry" emptyMessage="No dates added" editable="true" tableStyle="width:auto">
<p:ajax event="rowEdit" listener="#{dataTableBean.onRowEdit}" update="entries"/>
<p:column headerText="Dates">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{entry.date}">
<f:convertDateTime pattern="MM/dd/yyyy" />
</h:outputText>
</f:facet>
<f:facet name="input">
<p:calendar id="date" value="#{entry.date}" pattern="MM/dd/yyyy" placeholder="mm/dd/yyyy" mask="true" showOn="button" navigator="true"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor/>
</p:column>
<p:column>
<p:commandLink title="Remove date">
<h:outputText value="" styleClass="ui-icon ui-icon-trash"/>
<f:ajax event="click" listener="#{dataTableBean.entries.remove(entry)}" render="entries"/>
</p:commandLink>
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
DataTableBean.java
package com.aadhoc.test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.event.AjaxBehaviorEvent;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.event.RowEditEvent;
@ManagedBean(name="dataTableBean")
@SessionScoped
public class DataTableBean {
private List<DataTableEntry> entries = new ArrayList<>();
public List<DataTableEntry> getEntries() {
return entries;
}
public void setEntries(List<DataTableEntry> entries) {
this.entries = entries;
}
public void onAdd(AjaxBehaviorEvent event) {
DumpList("onAdd, before");
UIComponent component = event.getComponent();
UIComponent dateComp = component.findComponent("date");
Date date = (Date) ((UIInput)dateComp).getValue();
DataTableEntry entry = new DataTableEntry();
entry.setDate(date);
getEntries().add(entry);
sortEntries(getEntries());
DumpList("onAdd, after");
}
public void onRowEdit(RowEditEvent event) {
DumpList("onRowEdit, before");
// Get entries via DataTable#getValue because in real code
// I don't have direct access to entries.
DataTable dt = (DataTable) event.getSource();
@SuppressWarnings("unchecked")
List<DataTableEntry> entries = (List<DataTableEntry>) dt.getValue();
sortEntries(entries);
DumpList("onRowEdit, after");
}
private void DumpList(String msg) {
System.out.println(msg);
for (DataTableEntry entry : entries) {
System.out.println(entry);
}
}
private <T> void sortEntries(List<DataTableEntry> entries) {
entries.sort(new Comparator<DataTableEntry>() {
@Override
public int compare(DataTableEntry entry1, DataTableEntry entry2) {
return entry1.getDate().compareTo(entry2.getDate());
}
});
}
}
DataTableEntry.java
package com.aadhoc.test;
import java.io.Serializable;
import java.util.Date;
public class DataTableEntry implements Serializable {
private static final long serialVersionUID = -2513940455250513641L;
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String toString() {
return getClass().getSimpleName()+"[Date:"+getDate()+"]";
}
}
Upvotes: 2
Views: 2413
Reputation: 808
I encountered the same problem.
Workaround : define the widgetVar attribute in the <p:dataTable widgetVar="datatableVar" ...>
and add this line at the end of your onRowEdit function :
RequestContext.getCurrentInstance().execute("PF('datatableVar').filter()");
This will force the rendering of the entire datatable.
Upvotes: 2