0 Replies Latest reply on Mar 10, 2014 8:58 AM by lucias

    Ajax + server pagination with datascroller

    lucias

      I 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!