Ajax + server pagination with datascroller
lucias Mar 10, 2014 8:58 AMI have developed (almost copied if i have to be honest ) an ExtendedDataModel that supports Pagination on the server side (by querying a db). Everything works as i expected, the pagination occurs and works fine. But, at the same time, i want to load the data of each page in client side with ajax, so i would also like to set the clientRows property for my extendedDataTable, and not only the rows attribute that divides each logical page. In general, i want to be able to set clientRows < rows, so i get server side pagination + ajax loading in each page. But, at the moment this only works when i set clientRows=rows which obviously isn´t what i need.
What is happening right now is that if i set the clientRows attribute, then the walk method recieves a range which goes only up to clientRows rows, and ignores the row attribute completely. If i dont set clientRows, then the row attribute is passed (ok!) as the range limit (totalRows). I don´t know if this helps.
How can i accomplish this?
I post relevant code below.
The PaginationDataModel is as follows:
public abstract class PaginationDataModel<T> extends ExtendedDataModel<T> { private SequenceRange cachedRange; private Integer cachedRowCount; private List<T> cachedList; private Object rowKey; /** * * @param firstRow * @param numRows * @return */ public abstract List<T> getDataList(int firstRow, int numRows); public abstract Object getKey(T t); public abstract int getTotalCount(); @Override public void walk(FacesContext ctx, DataVisitor dv, Range range, Object argument) { SequenceRange sr = (SequenceRange) range; if (cachedList == null || !equalRanges(cachedRange, sr)) { cachedList = getDataList(sr.getFirstRow(), sr.getRows()); cachedRange = sr; } for (T t : cachedList) { if (getKey(t) == null) { /* * the 2nd param is used to build the client id of the table * row, i.e. mytable:234:inputname, so don't let it be null. */ throw new IllegalStateException("found null key"); } dv.process(ctx, getKey(t), argument); } } /* * The rowKey is the id from getKey, presumably obtained from * dv.process(...). */ @Override public void setRowKey(Object rowKey) { this.rowKey = rowKey; } @Override public Object getRowKey() { return rowKey; } @Override public boolean isRowAvailable() { return (getRowData() != null); } @Override public int getRowCount() { if (cachedRowCount == null) { cachedRowCount = getTotalCount(); } return cachedRowCount; } @Override public T getRowData() { for (T t : cachedList) { if (getKey(t).equals(this.getRowKey())) { return t; } } return null; } protected static boolean equalRanges(SequenceRange range1, SequenceRange range2) { if (range1 == null || range2 == null) { return range1 == null && range2 == null; } else { return range1.getFirstRow() == range2.getFirstRow() && range1.getRows() == range2.getRows(); } } /* * get/setRowIndex are used when doing multiple select in an * extendedDataTable, apparently. Not tested. Actually, the get method is * used when using iterationStatusVar="it" & #{it.index}. */ @Override public int getRowIndex() { if (cachedList != null) { ListIterator<T> it = cachedList.listIterator(); while (it.hasNext()) { T t = it.next(); if (getKey(t).equals(this.getRowKey())) { return it.previousIndex() + cachedRange.getFirstRow(); } } } return -1; } @Override public void setRowIndex(int rowIndex) { int upperBound = cachedRange.getFirstRow() + cachedRange.getRows(); if (rowIndex >= cachedRange.getFirstRow() && rowIndex < upperBound) { int index = rowIndex % cachedRange.getRows(); T t = cachedList.get(index); setRowKey(getKey(t)); } } @Override public Object getWrappedData() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void setWrappedData(Object data) { throw new UnsupportedOperationException("Not supported yet."); } public List<T> getCachedList() { return cachedList; } }
And the extendedDataTable with dataScroller:
<rich:panel id="idPanel"> <rich:extendedDataTable value="#{someBean.someModel}" id="tableId" selectionMode="#{someBean.selectionMode}" selection="#{someBean.selection}" rows = "20" clientRows="#{someBean.clientRows}" var="someItem" style="height:300px;"> <a4j:ajax execute="idPanel" event="selectionchange" listener="# {someBean.selectionListener}" render="@none" /> columns and more columns... <f:facet name="footer"><rich:dataScroller for="tableId" page="#{someBean.currentPage}" /></f:facet> </rich:extendedDataTable> </rich:panel>
Thank you and excuse my english!