12 Replies Latest reply on Feb 4, 2009 11:42 AM by Jalal ul deen

    Problem with ExtendedDataModel and rich:datascroller

    Hristo Mitkov Newbie

      Hi,
      I've read a lot of posts regarding pagination and rich:datascroller but I still can't solve one problem.
      I'm trying to make a real pagination in the database by querying for just the number of results that I need. Otherwise rich:datascroller returns the whole result set and then only shows a small part of it which does not work well for large result sets.
      My problem is that I cannot set my datascroller to show the correct number of pages using an ExtendedDataModel. The reason for this is that ListSequenceDataModel is used for calculating the number of pages instead of my ExtendedDataModel. This looks more like a bug in Richfaces DataScroller but I'm not sure.
      Here is the details:
      I have TestDataModel class which extends SerializableDataModel where in wrappedData I return just 10 elements but my getRowCount method returns the number of all records in the database which is 500. The datascroller though shows that there is only one page.
      I debug the richfaces code to see how the datascroller is rendered.
      This is done mainly in DatascrollerTemplate and DataScrollerRenderer in package org.richfaces.renderkit.html. As expected the datascroller uses the DataModel of the DataTable to calculate the number of pages:
      org.richfaces.component.UIDatascroller.getRowCount(UIData data)
      and after:
      UIDataAdapter.getRowCount(){
      ... return getExtendedDataModel().getRowCount();
      }

      Here getExtendedDataModel() returns an instance of ModifiableModel which field "originalModel" contains my custom TestDataModel. So modifiableModel.getOriginalModel.getRowCount will return 500 as I need. But look at the implementation of modifiableModel.getRowCount:

      public int getRowCount() {
      return delegate.getRowCount();
      }

      !!!???
      delegate is an instance of ListSequenceDataModel which contains the list wrappedKeys. So getRowCount() returns wrappedKeys.size() which is 10 so the datascroller renders with only one page.

      At the time of rendering the dataTable when the model is created () both fields: originalModel and delegate are set to TestDataModel. But at some point before delegate is set to ListSequenceDataModel and returns the size of the list.

      Here is an example of my code:

      @Name("testDataModel")
      @Scope(ScopeType.SESSION)
      public class TestDataModel extends SerializableDataModel {
      
       private Integer currentPk;
      
       private boolean detached = false;
       private List<Integer> wrappedKeys = null;
       private final Map<Integer, User> wrappedData = new HashMap<Integer, User>();
       private Integer rowCount;
      
       @In(create = true)
       private UserService userManager;
      
       @Override
       public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
       if (detached){
       for (Integer key : wrappedKeys) {
       setRowKey(key);
       visitor.process(context, key, argument);
       }
       } else {
       int firstRow = ((SequenceRange) range).getFirstRow();
       int numberOfRows =((SequenceRange) range).getRows();
       wrappedKeys = new ArrayList<Integer>();
       for (User user : userManager.findUsersPaged(firstRow, numberOfRows, null, null)) {
       wrappedKeys.add(user.getId());
       wrappedData.put(user.getId(), user);
       visitor.process(context, user.getId(), argument);
       }
       }
       }
      
      ...
       @Override
       public int getRowCount() {
       rowCount = userManager.countUsers();
       return rowCount;
       }

      This is my seam managed component:
      @Scope(ScopeType.SESSION)
      @Name("userManager")
      public class UserAction implements UserService{
      ...
       public List<User> findUsersPaged(int firstRow, int numberOfRows, String sortField, boolean descending) {
       List<User> users = entityManager.createQuery("select u from User u").setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
       return users;
       }


      Another thing is that there is no way to set the number of pages directly to the UIDatascroller component either by an attribute or by the API
      I'm very interested to see how this problem can be solved.
      If anyone is familiar with this could you give me a tip.

      Many thanks,
      Hristo