Search code examples
primefacesjsf-2.2primefaces-datatable

Primefaces datatable filtered rows become blank after sort


My Primefaces table is non-lazy loaded, displays POJOs and support default filtering and sorting.

Filtering works fine alone, sorting works fine alone. But when I type something in any column's filter, and then click a sort key (on any column), all the filtered objects become blank (the number of rows is the correct filtered rows). If I erase the last character in the filter (thus triggering filter), all the filtered rows re-appear OK and the sort order is honored. Here is my datatable:

        <p:dataTable id="assets" rows="10" paginator="true" filteredValue="#{assetBean.filteredAssets}" 
value="#{assetBean.assetGroups}" var="asset">
            <p:column headerText="Location" filterBy="#{asset.installation}" field="installation">
            </p:column>
            <p:column headerText="Name" filterBy="#{asset.name}" field="name">
            </p:column>
            <p:column headerText="Type" filterBy="#{asset.udt_id}" field="udt_id">
            </p:column>
        </p:dataTable>

I tried debugging with logging in the setter and getter of filterValue like this in AssetBean.java:

@javax.inject.Named
@javax.faces.view.ViewScoped
public class AssetBean implements java.io.Serializable {

private List<Asset> filteredAssets;

public List<Asset> getFilteredAssets() {
    Logger.getLogger(AssetBean.class.getName()).log(Level.INFO, "getFilteredAssets {0}", filteredAssets.size());
    return filteredAssets;
}
public void setFilteredAssets(List<Asset> filteredAssets) {
    this.filteredAssets = filteredAssets;
    Logger.getLogger(AssetBean.class.getName()).log(Level.INFO, "setFilteredAssets {0}", this.filteredAssets.size());
    if (filteredAssets.size()>0) {
        Asset a = this.filteredAssets.get(0);
        Logger.getLogger(AssetBean.class.getName()).log(Level.INFO, "first name {0}", a.getName());
    }
}
....

These are interesting things noted:

  1. getFilteredAssets is never called
  2. setFilteredAssets is first called as expected. When a sortKey is pressed, setFilteredAssets is found to be passed a List of the correct size, but the Asset.name is null. When the filter is changed, setFilteredAssets is found to be passed a List of the correct size, and correct contents so the datatable shows correct data again.

Debugging in the browser shows that the ajax response indeed contains empty rows. For the problematic sort, the POST body of the ajax request contains:

{javax.faces.partial.ajax: "true", ...
main-form:assets_sorting: "true", main-form:assets_skipChildren: "true", 
main-form:assets_sortKey: "main-form:assets:j_idt16", 
main-form:assets_sortDir: "-1", 
main-form:assets:j_idt14filter: "",
main-form:assets:j_idt15filter: "Pla",
main-form:assets:j_idt16filter: "",
}

When I changed the filter, the POST body of the ajax request is the same as above, except main-form:assets:j_idt15filter contains the new value and main-form:assets_sorting, sortKey, sortDir are missing.

My environment TomEE (javaee-web-api 7.0), Primefaces 10.0.0, Omnifaces 3.13, OpenJDK 11.


Solution

  • I solved by a workaround by wrapping a placeholder ajax listener for the sort event to trigger a filter request:

    <p:ajax event="sort" listener="#{assetBean.sortPlaceholder}" oncomplete="PF('data-table1').filter()"/>
    

    This seems to be a bug in Primefaces.