'Richfaces 3 how to make datascroller do true pagination

I'm trying to figure out how to do true pagination with richfaces datascroller.

Currently my query pulls all of the data from a table and i want it so when you click the next button of the datascroller, it will query the db for the next 20 rows.

I understand how to write the query to limit the rows, but i'm not sure how to get the datascroller's next button to call a specific method.

I see there are many people posting on the Richfaces forums with potential solutions, but they all use a dataModel. Since i'm not using an ORM, i'm not sure how i can fit these solutions to what i have.

Any help is appreciated.

<rich:extendedDataTable id="resultsTable" value="#{tableBacking.results}" var="results" sortMode="single" rowKeyVar="row">
    <rich:columns value="#{tableBacking.columns == null ? '' : tableBacking.columns}" var="columns" index="ind" id="column#{ind}" sortBy="#{results[ind].data}" rendered="#{tableBacking.columns != null}">
        <f:facet name="header">
            <h:outputText value="#{columns.columnDescription}" />
        </f:facet>

        <h:outputText value="#{results[ind].data}" />

    </rich:columns>

</rich:extendedDataTable>

<rich:datascroller for="resultsTable" page="#{tableBacking.page}" renderIfSinglePage="false" />

Backing bean

public class TableBacking {
    private List<List<TableData>> results = null;
    private int page = 0;

    public int getPage() {
    return page;
    }
    public void setPage(int page) {
    this.page = page;
    }
    public List<List<TableData>> getResults() throws Exception {
    return results;
    }
    public void setResults(List<List<TableData>> results) {
    this.results = results;
    }

    private void getData(String whereClause) {

    try {
    DataDao dd = new DataDao();
    results = dd.getData();    // dd.getData just runs a query on a table and puts the results in a List of lists.
    } catch (Exception e) {}
}


Solution 1:[1]

Try to do this :

JSF Stuff:

 <rich:dataTable id="listTable" var="record" rows="10" value="#{personBean.data}">
   ....
   <f:facet name="footer">
      <rich:column colspan="8">
        <rich:dataScroller page="#{personBean.page}" for="listTable"
                scrollListener="#{personBean.scrollPage}" render="listTable" />
      </rich:column>
      Records  : #{personBean.data.size()}
   </f:facet>
 </rich:dataTable>

Java BackBean Stuff:

public class PersonBean {
    // List of Persons
    private PagedList<Person> data;

    // Current page
    private Integer page;

    // Default rows to display
    private Integer rows = 10;

    // Persistence layer
    private DaoService daoService;

    @PostConstruct
    public void init(){
        page= 1;
    }

    // Event trigger on scroll page
    public void scrollPage(DataScrollEvent ev) {
        log.debug("Scroll event");
        reset();

        // getPersons execute 2 queries : the first query is the count(*) and the result is set in TotalElements 
        // the second query gets the 'n' records defined in rows , something like this  :
        //  select * from Persons  LIMIT page*rows, (page*rows) + rows and the result is set in Content
        Page<Person> pageResult = this.daoService.getPersons(filter, page - 1, rows);

        // Now create a pagedList with the constructor 
        this.data = new PagedList<Person>(pageResult.getContent(), (int) pageResult.getTotalElements(), this.pageSize);
    }
}

Java PagedList

public final class PagedList<E> extends AbstractList<E> {

    private final List<E> lista;
    private final int total;
    private final int pageSize;

    public PagedList(List<E> lista, int total, int pageSize) {
        this.lista = lista;
        this.total = total;
        this.pageSize = pageSize;
    }

    public int size() {
        return total;
    } 

    public E get(int i) {
        i = i % this.pageSize;
        return lista.get(i);
    }
}

The trick is to set the total property of PagedList class with the count of the dataTable in the database and only set the paged elements in the list of PageList.

Sorry for my bad english :P

Solution 2:[2]

You need to bind your rich:extendedDataTable to an attribute in your backing bean.

Java

private HtmlExtendedDataTable Table;
//Getter and setter

After that you bind your view

xhtml

<rich:extendedDataTable id="resultsTable" value="#{tableBacking.results}" var="results" sortMode="single" rowKeyVar="row" binding="#{tableBacking.Table}">

Richfaces HtmlExtendedDataTable has a method to check how many rows are displayed per page, called getRows(). When bean initializes just load the first page values, according to that (you can load only the id's of the elements on the rest of the pages and later when you're going to access the page load them based on the id).

<rich:datascroller/> also has an event which is fired when a page button is clicked and you can acquire that from your backing bean in this way:

xhtml

 <f:facet name="footer">
<rich:datascroller id="ds"
                scrollerListener="#{tableBacking.actionOnPageChange}" />
</f:facet>

Java

public String actionOnPageChange(DataScrollerEvent event)

This DataScrollerEvent includes what page has been clicked by the user, which you can get using getNewScrolVal(). When that happens just load the values of the corresponding page in your table and that's it.

Solution 3:[3]

The best solution I've found is mapping the "value" attribute of the dataTable to a org.richfaces.model.ExtendedTableDataModelproperty. You then initialize the ExtendedTableDataModel with an instance of org.richfaces.model.DataProvider. Sample:

In the view:

<rich:dataTable id="table" value="#{bean.model}" rows="#{bean.rows}">
    <!-- columns -->
    <f:facet name="footer">
        <rich:dataScroller for="table"/>
    </f:facet>
</rich:dataTable>

In the bean:

@ManagedBean
public class Bean {
    private int rows = 15; // the ammount of rows per page.
    private org.richfaces.model.ExtendedTableDataModel model = new org.richfaces.model.ExtendedTableDataModel(
        new org.richfaces.model.DataProvider(
        public int getRowCount() {
            // count your rows.
        }

        public List<T> getItemsByRange(int first, int quantity) {
            // fetch the page's rows. 
        }

        public T getItemByKey(Object o) {
            return null; // no need to implement this.
        }

        public Object getKey(T t) {
            return null; // no need to implement this.
        )
    );

    public int getRows() { return rows; }
    public ExtendedTableDataModel getModel() { return model; }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Daniel Szalay
Solution 2
Solution 3 Martín Straus