I have a button on a page that causes my data table to refresh via an AJAX request. Something like this:
Add this PhaseListener to your application and both sorting and filtering will be kept after updating the DataTable.
public class DataTableUpdatePhaseListener implements PhaseListener {
private static final long serialVersionUID = 1L;
@Override
public void afterPhase(PhaseEvent event) {
// Nothing to do here
}
@Override
public void beforePhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
if (!facesContext.isPostback()) {
return;
}
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
if (partialViewContext != null) {
Collection renderIds = partialViewContext.getRenderIds();
for (String renderId : renderIds) {
UIComponent component = facesContext.getViewRoot().findComponent(renderId);
if (component instanceof DataTable) {
DataTable table = (DataTable) component;
if (!table.isLazy()) {
updateDataTable(table);
}
}
}
}
}
@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
private void updateDataTable(DataTable table) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null || table == null) {
return;
}
// Reapply filtering
if (!table.getFilters().isEmpty()) {
FilterFeature filterFeature = new FilterFeature();
filterFeature.decode(facesContext, table);
} else {
table.setFilteredValue(null);
}
// Reapply sorting
ValueExpression tableSortByVE = table.getValueExpression("sortBy");
if (tableSortByVE != null) {
String tableSortByExpression = tableSortByVE.getExpressionString();
// Loop on children, that are the columns, to find the one whose order must be applied.
for (UIComponent child : table.getChildren()) {
Column column = (Column) child;
ValueExpression columnSortByVe = column.getValueExpression("sortBy");
if (columnSortByVe != null) {
String columnSortByExpression = columnSortByVe.getExpressionString();
if (tableSortByExpression != null && tableSortByExpression.equals(columnSortByExpression)) {
// Now sort table content
SortFeature sortFeature = new SortFeature();
sortFeature.sort(facesContext, table, tableSortByVE,
SortOrder.valueOf(table.getSortOrder().toUpperCase(Locale.ENGLISH)),
table.getSortFunction());
break;
}
}
}
}
}
}
This is for non-lazy data tables. Data tables using a lazy model do not require this, as the lazy model will take care of sorting and filtering. For non-lazy data tables, this should work with both single and multiple column sorting but there is a bug in Primefaces that makes DataTable loose its MultiSortMeta between postbacks when updating the table. This means that the columns selected for sorting before postback are completely lost from FacesContext and component state and cannot be retrieved anymore upon postback. I'll look more into this later and provide an update if I manage to find a workaround or maybe Primefaces will fix it soon.