p:datatable loses sort column and order after ajax refresh p:datatable loses sort column and order after ajax refresh ajax ajax

p:datatable loses sort column and order after ajax refresh


I wrote an extension to @truemmer's solution. His reverts the sorting order back to the default, where as mine will reverts to the previous sort the user selected.

function postAjaxSortTable(datatable){    var selectedColumn = datatable.jq.find('.ui-state-active');    if(selectedColumn.length <= 0)    {        return;    }    var sortorder = "ASCENDING";    if(selectedColumn.find('.ui-icon-triangle-1-s').length > 0)    {        sortorder = "DESCENDING";    }    datatable.sort(selectedColumn, sortorder);}

Updating the same table as truemmer's works like this:

<p:commandButton value="refresh" action="#{tableController.refreshPrices}" update="myTable" oncomplete="postAjaxSortTable(myTableWidget)" />

EDIT: Primefaces 4.0 MultiSort support

function postAjaxSortTable(datatable) {    var selectedColumn = undefined;    // multisort support    if(datatable && datatable.cfg.multiSort) {        if(datatable.sortMeta.length > 0) {            var lastSort = datatable.sortMeta[datatable.sortMeta.length-1];            selectedColumn = $(document.getElementById(lastSort.col));        }    } else {        selectedColumn = datatable.jq.find('.ui-state-active');    }    // no sorting selected -> quit    if(!selectedColumn || selectedColumn.length <= 0) {        return;    }    var sortorder = selectedColumn.data('sortorder')||"DESCENDING";    datatable.sort(selectedColumn, sortorder, datatable.cfg.multiSort);}


First of all, there is an open ticket on the PrimeFaces Issue Tracker, which targets this question but was recently labeled as "won't fix".

Nevertheless, I found a nice workaround. The sorting of PrimeFaces tables can be triggered by calling an undocumented JavaScript method on the datatable's widget. The following might not work for future releases of PrimeFaces, but it does for 3.4.2:

Just add the following to your component, which triggers the update:

oncomplete="myTableWidget.sort($(PrimeFaces.escapeClientId('#{p:component('sortColumnId')}')), 'ASCENDING')"

The table might look like this:

<p:dataTable id="myTable"             widgetVar="myTableWidget"             value="#{myArticles}"             var="article"             sortBy="#{article.price}"             sortOrder="ASCENDING">    ...    <p:column id="price" sortBy="#{article.price}">        <f:facet name="header">            <h:outputText value="Price" />        </f:facet>        <h:outputText value="#{article.price}" />    </p:column></p:dataTable>

So updating the table could work like this.

<p:commandButton value="refresh" action="#{tableController.refreshPrices}" update="myTable" oncomplete="myTableWidget.sort($(PrimeFaces.escapeClientId('#{p:component('price')}')), 'ASCENDING')" />


EDIT:

Solution posted below (LazyTable) works for the p:dataTable backed with LazyDataModel. Overriden load method is called after every update/refresh on the desired table and it handles sort properly. The problem with simple p:dataTable is that it performs predefined sort only on the first load, or after the click on sort column. This is a normal behaviour of a simple table.

So what are your possibilities for simple table :

  • Don't sort the table after update, but remove the sort column so end user is not missinformed. Add this to your action listener or action method for your update button :

    UIComponent table  = FacesContext.getCurrentInstance().getViewRoot().findComponent(":dataTablesForm:dataTableId");table.setValueExpression("sortBy", null);
  • Update the sort of the table manually by script. This is not the best solution, but primefaces doesn't provide any client side function for "resorting" the table. Basically you know that only one column at a time can be sorted and this column has a .ui-state-active. You can use it in a script and trigger 2 clicks on that column (1. click - other sort order, 2. click - back to current sort order).

     <h:form id="mainForm">  <div id="tableDiv">   <p:dataTable id="dataTable" var="item" value="#{testBean.dummyItems}">      .      .      .   </p:dataTable>    <p:commandButton value="Refresh" oncomplete="refreshSort();" update=":mainForm:dataTable"/> </div>

    And script function :

    function refreshSort(){jQuery('#tableDiv').find('.ui-state-active').trigger('click');jQuery('#tableDiv').find('.ui-state-active').trigger('click');}

I know this is not the best workaround, but it works. You can use it as an inspiration to make something better.

LazyTable

IMHO the most proper way is to update directly the component you want. So for example :

<h:form id="dataTableForm">  <p:dataTable id="dataTableToUpdate">    .    .    .  </p:dataTable>  <p:commandButton value="Refresh" update=":dataTableForm:dataTableToUpdate" /></h:form>

It should work fine in this scenario (I suppose it is your purpose) : Open the .xhtml with your p:dataTable, sort some column (keep the facelet opened), update dataTables data from another .xhtml for example, click on refresh button. The dataTable should show your added value in correct (previously chosen) sort order - sorting was performed after update.

Hope it helped !