Pagination with Iterator Tag in ADF Applications

Pagination is a feature that any developer may need to implement when working with the large data. When search engine returns results that can not comfortably fit within one screen, one option we can do is to use a scrollable table. The other option will be using pagination. Pagination is used in almost every web application to divide returned data and display it on multiple pages. One way of implementing pagination on ADF applications is by using af:iterator tag.

This is a component that does iteration and  allows to render collection of data (similar to af:table tag). Each child is repeatedly stamped as many times as necessary. Iteration is done starting at the index given by the "first" attribute, for as many indices as specified by the "rows" attribute. If "rows" returns 0, then the iteration continues until there is no more elements left in the collection. Rows attribute holds the value for the maximum number of rows to display in a single range of rows (The default is 25).

<af:iterator> works with a JSF DataModel or CollectionModel. It can also be bound to EL expressions that use component-managed EL variables (such as the "var" variable on an <af:table>).

The value attribute of this tag is used for the binding, the data model being used by this component. The specific model class is oracle.adf.view.faces.model.CollectionModel (other model instances, like java.util.List , array, and javax.faces.model.DataModel can be used). This component will automatically convert the instance into a CollectionModel.

For the steps below I used HR schema and employees table along with JDeveloper 11g Release 2.

Let's build our page. First create a Fusion Web Application (I named it as PagingTest). Then rigth click on Model project to create Bussiness Components from Tables.



After defining the database connection, query the database and create an entity object and Entity-based-view Object for the employees table and click Finish to close the wizard.


Then create a jsf page with the Oracle Three Column Layout template. 


Drop Employees data contol to the center facet to create ADF Read Only Table and select name and last name properties deleting the rest. We do that to create bindings and use it directly.


Now lets create a managed bean to handle the button clicked events and define that bean in adfc-config.xml with the backingBean scope.


package mybeans;

import javax.faces.event.ActionEvent;

import org.apache.myfaces.trinidad.component.UIXIterator;

public class MyPagingBean {
    private UIXIterator employeesIterator;
    private int rowsPerPage=10;

    public void firstActionListener(ActionEvent actionEvent) {        
        this.getEmployeesIterator().setFirst(0);
    }

    public void previousActionListener(ActionEvent actionEvent) {
        this.getEmployeesIterator().setFirst(this.getEmployeesIterator().getFirst() - rowsPerPage);
    }
    public void nextActionListener(ActionEvent actionEvent) {
        this.getEmployeesIterator().setFirst(this.getEmployeesIterator().getFirst() + rowsPerPage);
    }
    public void lastActionListener(ActionEvent actionEvent) {
        int totalPages = this.getEmployeesIterator().getRowCount() / rowsPerPage;
        int rowCount = totalPages * rowsPerPage;
        if (rowCount == this.getEmployeesIterator().getRowCount()) {
            rowCount = rowCount - rowsPerPage;
        }
        this.getEmployeesIterator().setFirst(rowCount);
    }
    public void setEmployeesIterator(UIXIterator employeesIterator) {
        this.employeesIterator = employeesIterator;
    }

    public UIXIterator getEmployeesIterator() {
        return employeesIterator;
    }

    public void setRowsPerPage(int rowsPerPage) {
        this.rowsPerPage = rowsPerPage;
    }

    public int getRowsPerPage() {
        return rowsPerPage;
    }
}


Now click on the source tab for the employees.jsf and manualy change the <af:table> tag to <af:iterator> tag. You can see what it should like after changing it. 

Before:

<af:table value="#{bindings.EmployeesView1.collectionModel}" var="row"
rows="#{bindings.EmployeesView1.rangeSize}"
emptyText="#{bindings.EmployeesView1.viewable ? 'No data to display.' : 'Access Denied.'}"
fetchSize="#{bindings.EmployeesView1.rangeSize}" rowBandingInterval="0" id="t1">
                        <af:column sortProperty="#{bindings.EmployeesView1.hints.FirstName.name}" sortable="false"
                                   headerText="#{bindings.EmployeesView1.hints.FirstName.label}" id="c1">
                            <af:outputText value="#{row.FirstName}" id="ot1"/>
                        </af:column>
                        <af:column sortProperty="#{bindings.EmployeesView1.hints.LastName.name}" sortable="false"
                                   headerText="#{bindings.EmployeesView1.hints.LastName.label}" id="c2">
                            <af:outputText value="#{row.LastName}" id="ot2"/>
                        </af:column>
                    </af:table>


After:

<af:panelGroupLayout id="pc1" layout="vertical">
        <af:iterator id="i11" var="row" 
value="#{bindings.EmployeesView1.collectionModel}"
binding="#{backingBeanScope.myPagingBean.employeesIterator}"
rows="#{backingBeanScope.myPagingBean.rowsPerPage}">

<af:panelGroupLayout id="pc15" layout="horizontal">
<af:panelGroupLayout id="pgl12" layout="horizontal">
                        <af:outputText id="id12" value="#{row.bindings.FirstName.inputValue}"/>
                        </af:panelGroupLayout>
<af:spacer width="10" height="20" id="s1"/>
<af:panelGroupLayout id="pgl14" layout="horizontal">
<af:outputText id="id14" value="#{row.bindings.LastName.inputValue}"/>
</af:panelGroupLayout>
</af:panelGroupLayout>
</af:iterator>
</af:panelGroupLayout>

If you noticed we copied and used value, bindings and rows properties from the table component. Now drag and drop Panel Form Layout to the first facet of the page and drop 4 Button components into it and name them First, Next, Last, Previous. For each bbutton set the ActionListener property as to the managed bean methods we created as follow;

First -> #{backingBeanScope.myPagingBean.firstActionListener}
Next  -> #{backingBeanScope.myPagingBean.nextActionListener}
Last  -> #{backingBeanScope.myPagingBean.lastActionListener}
Previous -> #{backingBeanScope.myPagingBean.previousActionListener}

Now save all and run the page. You will see we have successfully used iterator tag for our custom paging. We can also disable the Previos or Next buttons when we are on the first and last page. We can also create more sophisticated rows that can be used for navigation like editing an employee.

Comments:

Pretty cool,Gokhan, and probably a useful technique for some other use cases. But if I want a paging table, rather than the scrolling table provided by the af:table, why wouldn't I use a tr:table, instead of doing this coding?

Posted by John Flack on January 06, 2012 at 09:20 AM CET #

Hi,

to call "getRowCount()" on a very large data set is not the best practise I think, I would use getEstimatedRowCount() instead.

Martin

Posted by Martin on March 03, 2012 at 12:03 PM CET #

The af:table is another option that can be used for iteration. However it is usually useful for Structured Data. The underlying model class is org.apache.myfaces.trinidad.model.CollectionModel The table will automatically convert the instance into this CollectionModel. Also when iterating thru the collection, a column will not create any child components per row. Instead, each child is repeatedly rendered (stamped) once per row. Because of this behavior, some components many not work inside the table.

Posted by Gokhan Gungor on March 06, 2012 at 10:33 AM CET #

Martin,
In some cases where you need EXACT number of rows in an object, using getEstimatedRowCount() may not be preferred way. The data can be deleted or inserted in the back-end at the same time, causing this method displaying wrong number. However I agree getEstimatedRowCount() will save database round trip in most cases.

Posted by Gokhan Gungor on March 06, 2012 at 11:02 AM CET #

Hi,

This post was pretty cool..........How can we achieve selectAll/DeselectAll using af:iterator

Posted by guest on April 27, 2012 at 03:30 PM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Oracle ECEMEA Partner Hubs Migration Center Team

We share our skills to maximize your revenue!
Our dedicated team of consultants can rapidly and successfully assist you to adopt and implement the latest of Oracle Technology in your solutions.

Stay Connected
partner.imc
@
beehiveonline.oracle-DOT-com
Google+

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
2
3
4
5
6
9
10
11
12
13
14
16
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today