Thursday, October 28, 2010

ADF UI: Pagination (Navigation using First, Previous, Next, Last buttons) using <af:iterator>

It was a tough time for me to achieve pagination (i.e., navigating through a set of records using First, Previous, Next, Last buttons) in one of my ADF pages. I searched in net for any solution, but finally convinced that there is no declarative way to achieve this functionality in ADF. And, I also found that this concept of pagination was declarative in OAF and this had been replaced by ADF table scroll navigation. So, I went ahead and did some research and developed my own pagination technique using <af:iterator>. The below steps explain the use case and how to achieve the same.

Sample Use Case:
For example, we have a list of employees (say 50) and we want to display 5 employees at a time and on clicking 'Next' button we want to display next 5 records and so on. Similarly, on clicking 'Previous' button we want to display previous 5 records. The 'First' and 'Last' buttons should take use to the first 5 records and last 5 records respectively.
One more challenge to this use case is that we want to disable the 'Previous' button, if there are no more previous records and vice versa. Similarly, we want to disable the 'First' and 'Last' buttons if the current list is first set or last set of records respectively. Achieving this would be little tricky and we'll see how we can implement it.

Implementation Steps:
Here, I'm going to use <af:iterator> component to iterate through list of employee records and display the sets of records. IF you want to know how to use af:iterator, read my previous post.

1. First, tune the VO which you want to iterate. Tuning the VO will give us better performance if we tune as per our page range size requirements in UI (Screenshot below).


2. Specify the 'rangeSize' for the VOIterator in pageDef as the no. of rows you want to display for each time you click on 'Previous' and 'Next'.  This represents rowSet size (In the below code, I'm setting it to 5).
<iterator Binds="EmpDeptVO" RangeSize="5" DataControl="DemoAMDataControl" id="EmpDeptVOIterator" ChangeEventPolicy="ppr"/>


3. Drop af:iterator into jsff and add all VO attributes under iterator (refer to previous post). Please find the below code. Here, in pagination, the attribute 'first' of af:iterator will play a major role. It'll actually specify starting from which row number, the data is to be displayed. By default, let's keep it 0. Later, we'll update it to move back and forth on clicking 'Previous' and 'Next' buttons.
<af:iterator id="i1" value="#{bindings.EmpDeptVO.collectionModel}" var="row" varStatus="i" rows="#{bindings.EmpDeptVO.rangeSize}" binding="#{pageFlowScope.ExampleBean.employeeIterator}">


4. Add buttons 'First', 'Previous', 'Next' and 'Last' and specify the actionListeners as below.

<af:toolbar id="t1" partialTriggers="i1"> <af:commandToolbarButton text="First" id="ctb2" actionListener="#{pageFlowScope.ExampleBean.firstClicked}" disabled="#{pageFlowScope.ExampleBean.previousDisabled}"/> <af:commandToolbarButton text="Previous" id="ctb1" actionListener="#{pageFlowScope.ExampleBean.PreviousClicked}" disabled="#{pageFlowScope.ExampleBean.previousDisabled}"/> <af:commandToolbarButton text="Next" id="commandToolbarButton1" actionListener="#{pageFlowScope.ExampleBean.nextClicked}" disabled="#{pageFlowScope.ExampleBean.nextDisabled}"/> <af:commandToolbarButton text="Last" id="ctb3" actionListener="#{pageFlowScope.ExampleBean.lastClicked}" disabled="#{pageFlowScope.ExampleBean.nextDisabled}"/> </af:toolbar>


public void firstClicked(ActionEvent actionEvent) { UIXIterator empIterator = getEmployeeIterator(); empIterator.setFirst(0); AdfFacesContext.getCurrentInstance().addPartialTarget(empIterator); } public void PreviousClicked(ActionEvent actionEvent) { UIXIterator empIterator = getEmployeeIterator(); int first = empIterator.getFirst() - empIterator.getRows(); empIterator.setFirst(first); AdfFacesContext.getCurrentInstance().addPartialTarget(empIterator); } public void nextClicked(ActionEvent actionEvent) { UIXIterator empIterator = getEmployeeIterator(); int first = empIterator.getFirst() + empIterator.getRows(); empIterator.setFirst(first); AdfFacesContext.getCurrentInstance().addPartialTarget(empIterator); } public void lastClicked(ActionEvent actionEvent) { UIXIterator empIterator = getEmployeeIterator(); int noOfRows = empIterator.getRowCount(); int first = noOfRows- noOfRows%empIterator.getRows(); empIterator.setFirst(first); AdfFacesContext.getCurrentInstance().addPartialTarget(empIterator); }

5. And to achieve enabling/disabling the buttons, I wrote the below method based on the total no. of rows and current row set.
public boolean isPreviousDisabled() { UIXIterator empIterator = getEmployeeIterator(); int first = empIterator.getFirst(); if (first <= 0) { return true; } return false; } public boolean isNextDisabled() { UIXIterator empIterator = getEmployeeIterator(); int first = empIterator.getFirst() + empIterator.getRows(); int noOfRows = empIterator.getRowCount(); if (first >= noOfRows) { return true; } return false; }


Now, run the page and you'll see first 5 records and you can navigate to different row sets using the navigation buttons. Sample screen shots below:


5 comments:

  1. Did you know try the same for af:table / af:treetable. We need to do that for performance reasons?

    User needs to see first 10 rows and scroll needs to be disabled but instead we need to provide navigation buttons to next and previous

    ReplyDelete
  2. how can i access some value of the row ??

    ReplyDelete

Related Posts with Thumbnails