Thursday, May 30, 2013

Save the pagination state of Primfaces DataTable after navigate away from the page

How are you?

These days I'm working on a sample Application about uploading and retrieving blob images from oracle database using JSF2 and EJB/JPA (I will talk about the application in details and upload the source code as soon as I finish it Insha'Allah).

To display the table of employees in my application, I use Primfaces Datatable,it is an extremely useful component that can handle Pagination,sorting and filtering.All of these are manipulated with AJAX,but the problem is that its state, including current page, column sorted and filter criteria, is reverted to the default when you refresh the page or navigate away from the page containing the datatable.Of course there are many solutions and workarounds to save the state of <p:dataTable>.

My main concern here is how to save the state of pagination, in other words I want to save the current page number of the table so when the user select an employee from page 3 for example and navigate away to upload a photo for this employee, when he comes back to the page where the datatable is, the table is on the same page it was before,because the default is that the table reset its position to the first page instead of going back to the page the user was on. How can you force the dataTable to stay on the same page?

I found an elegant solution from here.As described in the above solution I do the following:
  1.  Create a sessionscoped managed bean to store the current page number of the table
  2.  Bind the first attribute of p:DataTable to a session variable in our bean
  3. Use onPageChange method to get the current datatable page number and update the variable with the new value,so when you navigate back to the datatable you will find that the current page is kept and correct as we preserve 'first ' of the datatable in a sessionscoped managed bean.
the code for our managed bean will be:
 package com.mb;  
 import java.io.Serializable;  
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.SessionScoped;  
 import org.primefaces.event.data.PageEvent;  
 import org.primefaces.component.datatable.DataTable;  
 @ManagedBean  
 @SessionScoped  
 public class DataTableControllPagination implements Serializable {  
      private static final long serialVersionUID = 1L;  
      protected int first;  
      public int getFirst() {  
           return first;  
      }  
      public void setFirst(int first) {  
           this.first = first;  
      }  
      public void onPageChange(PageEvent event) {  
           this.setFirst(((DataTable) event.getSource()).getFirst());  
      }  
 }  
The code for dataTable will be:
 <p:dataTable id="employeesTable" value="#{employeeWeb.allEmployees}"  
                     var="emp" emptyMessage="NO Employees" paginator="true"  
                     paginatorAlwaysVisible="false" rows="10" style="width: 100%;height: 150px" paginatorTemplate="{FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"  
                     first="#{dataTableControllPagination.first}">  
                <p:ajax event="page" listener="#{dataTableControllPagination.onPageChange}"/>  
This solution is working like a charm when I navigate back using the navigation commands and links but I noticed that when I hit "back" on the browser,the datatable will reset its state.The solution for back button in browser is as usual using filter to tell the browser not to cache the pages and send the request to the server when you press the browser back button so we can get the correct page number.

After adding the filter the problem is completely solved.If you want the code of custom filter or you do not know how to use it (although most of JSF Developers know this) wait for my next post I will upload the source code for uploading and displaying images including the filter.

See you soon and until then happy JSF developing.

Update on 14/9/2013:

If you want the code of Filter,Download the sample Application for this post from here.The filter is in com.filter package and will work for all .xhtml pages

9 comments:

  1. Your code isn't working for me. I'm using PF 4.0. Especially does the signature have to be
    public void onPageChange(AjaxBehaviorEvent event) {}
    and I don't need the ajax "page" event for this method to be called.

    ReplyDelete
  2. Last comment works succesfully with PF 5.2, thanks!

    ReplyDelete
  3. Good Job. It's working for me. Thanks!

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. it seem okay, but, if you open two tabs with the same page, this solution doesn't solves the problem

    ReplyDelete
    Replies
    1. i would suggest to use a map with the guids of tabs that are using the page

      http://terrcin.io/2015/05/10/browser-tab-tracking/

      Delete
  6. Since Primefaces v6.0.10 this is implemented in the dataTable component itself. See:
    http://www.primefaces.org/showcase/ui/data/datatable/tableState.xhtml

    ReplyDelete