3 Replies Latest reply on Oct 14, 2011 11:14 AM by richdeveloper

    How to load rows on demand using rich:scrollabledatatable

    richdeveloper

      Hi,

       

      I am using rich:scrollabledatatable to do virtual scrolling of a datatable. I also specified the "rows" attribute. But It brings all the rows very first time. Visually it feels like it is bringing all the rows on demand. But in reality it doesn't. Also I will be having millions of rows to display. So performance will be a issue.

       

      Following is my code snippet:

       

       

       

       

       

       

      <rich:scrollableDataTable id="jobListId" value="#{jobRows}" var="jobListRow"

             rendered="true" rowClasses="even-row, odd-row" rows="50" height="400px"

             rowKeyVar="row" ignoreDupResponses="true" style="z-index:-1;width:100%;">

             <rich:column label="Id" sortBy="#{jobListRow.jobId}"

              sortOrder="UNSORTED" width="100px" sortMode="multy">

        • 1. Re: How to load rows on demand using rich:scrollabledatatable
          richdeveloper

          OK.

           

          Finally I learned that just using "rows" attribute in rich:scrollableDataTable is not enough, one MUST implement ScrollableTableDataModel class and override loadData() method. So following is the code snippet:

           

          <rich:scrollableDataTable id="listId" value="#{jobRows}" var="jobListRow"

                 rendered="true" rowClasses="even-row, odd-row" rows="50" height="400px"

                 rowKeyVar="row" ignoreDupResponses="true" style="z-index:-1;width:100%;">

                 <rich:column label="Id" sortBy="#{jobListRow.jobId}"

                  sortOrder="UNSORTED" width="100px" sortMode="multy">

           

           

          Following in for ScrollableDataModel ....

           

          package com.xyz.action;

           

          import static org.jboss.seam.ScopeType.*;

           

          import java.util.ArrayList;

          import java.util.Date;

          import java.util.HashMap;

          import java.util.List;

          import java.util.Map;

           

          import org.apache.log4j.Logger;

          import org.jboss.seam.annotations.In;

          import org.jboss.seam.annotations.Name;

          import org.jboss.seam.annotations.Scope;

          import org.jboss.seam.faces.FacesMessages;

          import org.richfaces.model.ScrollableTableDataModel;

          import org.richfaces.model.SortOrder;

           

          import com.xyz.model.StatusType;

          import com.xyz.session.manager.JobManager;

           

          @Name(value = "jobScrollableDataModel")

          @Scope(SESSION)

          public class JobScrollableDataModel extends ScrollableTableDataModel implements java.io.Serializable

          {

           

            private static final Logger logger = Logger.getLogger(JobScrollableDataModel.class);

            private static final long serialVersionUID = 1L;

           

            private List<StatusType> selectedStatusTypes;

           

            private String fileSearchName = null;

           

            private Integer jobId = null;

           

            private Date fromDate;

           

            private Date toDate;

           

            private List<JobRow> jobRows;

           

            @In

            private JobManager jobManager;

           

            @In

            protected FacesMessages facesMessages;

           

            Map rangeMap = new HashMap();

           

            boolean render = false;

           

            int numberOfRows = 0;

           

            /**

             * @return the selectedStatusTypes

             */

            public List<StatusType> getSelectedStatusTypes()

            {

              return selectedStatusTypes;

            }

           

            /**

             * @param selectedStatusTypes the selectedStatusTypes to set

             */

            public void setSelectedStatusTypes(List<StatusType> selectedStatusTypes)

            {

              this.selectedStatusTypes = selectedStatusTypes;

            }

           

            /**

             * @return the fileSearchName

             */

            public String getFileSearchName()

            {

              return fileSearchName;

            }

           

            /**

             * @param fileSearchName the fileSearchName to set

             */

            public void setFileSearchName(String fileSearchName)

            {

              this.fileSearchName = fileSearchName;

            }

           

            /**

             * @return the jobId

             */

            public Integer getJobId()

            {

              return jobId;

            }

           

            /**

             * @param jobId the jobId to set

             */

            public void setJobId(Integer jobId)

            {

              this.jobId = jobId;

            }

           

            /**

             * @return the fromDate

             */

            public Date getFromDate()

            {

              return fromDate;

            }

           

            /**

             * @param fromDate the fromDate to set

             */

            public void setFromDate(Date fromDate)

            {

              this.fromDate = fromDate;

            }

           

            /**

             * @return the toDate

             */

            public Date getToDate()

            {

              return toDate;

            }

           

            /**

             * @param toDate the toDate to set

             */

            public void setToDate(Date toDate)

            {

              this.toDate = toDate;

            }

           

            /* (non-Javadoc)

             * @see org.richfaces.model.ScrollableTableDataModel#loadData(int, int, org.richfaces.model.SortOrder)

             */

            @Override

            public List<JobRow> loadData(int arg0, int arg1, SortOrder arg2)

            {

               try

              {

                if (selectedStatusTypes == null || selectedStatusTypes.isEmpty())

                {

                  this.setJobRows( new ArrayList<JobRow>());

                  this.render = false;

                }

                else

                {

          //        rangeMap.put(arg0, arg1);

          //        if(!rangeMap.containsKey(arg0))

          //        {

                    this.setJobRows( new ArrayList<JobRow>());

                    jobRows = jobManager.getListOfJobs(selectedStatusTypes,fileSearchName,fromDate,toDate,jobId,arg0,arg1,false);

                    int totalRows = jobRows.size();

                    if(totalRows > 0)

                    {

                      this.render = true;

                     }

                    else

                    {

                      this.render = false;

                    }

           

                }

           

              }

              catch (Exception e)

              {

                // TODO Auto-generated catch block

                e.printStackTrace();

              }

              return jobRows;

            }

           

             /* (non-Javadoc)

             * @see javax.faces.model.DataModel#getRowCount()

             */

            @Override

            public int getRowCount()

            {   

              return getTotalCount();

            }

           

            /* (non-Javadoc)

             * @see javax.faces.model.DataModel#getWrappedData()

             */

            @Override

            public Object getWrappedData()

            {

              throw new UnsupportedOperationException();

            }

           

            /* (non-Javadoc)

             * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)

             */

            @Override

            public void setWrappedData(Object arg0)

            {

              throw new UnsupportedOperationException();

           

            }

           

            public int getTotalCount()

            {

              int count = 0;

              try

              {

                count = jobManager.getTotalCountOfJobs(selectedStatusTypes, fileSearchName, fromDate, toDate);

                if(count == 0)

                {

                  this.render = false;

                }

             }

              catch (Exception e)

              {

                e.printStackTrace();

              }

              this.setNumberOfRows(count);

              return count;

            }

           

            /**

             * @return the jobRows

             */

            public List<JobRow> getJobRows()

            {

              return jobRows;

            }

           

            /**

             * @param jobRows the jobRows to set

             */

            public void setJobRows(List<JobRow> jobRows)

            {

              this.jobRows = jobRows;

            }

           

            public void clear()

            {

              try

              {

                logger.trace("clearing joblist !!");

                //clear the form data

                this.selectedStatusTypes = new ArrayList<StatusType>();

                this.fromDate = null;

                this.toDate = null;

                this.fileSearchName = null;

                this.jobId = null;

                this.render = false;

              }

              catch (Exception e)

              {

                logger.error("Problem with clear.", e);

              }

            }

           

           

            public void refreshJobList(boolean isClear)

            {

              logger.trace("refreshing job list !!");

              try

              {

                  if (getSelectedStatusTypes() != null && !isClear && getSelectedStatusTypes().isEmpty())

                {

                  this.setJobRows( new ArrayList<JobRow>());

                  facesMessages.addToControl("statusTypesId", "Please select at least one Status Type.", null);

                }

                  else

                  {

                    if(!this.render || this.getNumberOfRows() > 0) 

                    {

                      this.setJobRows( new ArrayList<JobRow>());

                      this.render = true;

                      this.loadData(0, 50, null);

                    }

                  }

              }

              catch (Exception e)

              {

                logger.error("Problem with refreshing job list. isClear=" + isClear + ", jobManager.getListOfJobs(" +

                    selectedStatusTypes + ", " + fileSearchName + ", " + fromDate + ", " + toDate, e);

              }

           

            }

           

            /**

             * @return the render

             */

            public boolean isRender()

            {

              return render;

            }

           

            /**

             * @param render the render to set

             */

            public void setRender(boolean render)

            {

              this.render = render;

            }

           

           

            /**

             * @return the numberOfRows

             */

            public int getNumberOfRows()

            {

              return this.numberOfRows;

            }

           

            /**

             * @param numberOfRows the numberOfRows to set

             */

            public void setNumberOfRows(int numberOfRows)

            {

              this.numberOfRows = numberOfRows;

            }

           

          }

           

          So It's working perfectly fine. It get chunks of rows via lazy loading. But the only problem is ...as I scroll through the SDT. Looks like it caches the range. So It calls loadData() multiple times. e.g. If first time it calls for range 0 to 50. Then next time it calls two times ...with range 0 to 50 and with new range 50 - 100....So as it progresses ...it keeps on calling for previous range....which will be performance degrde in long run..

           

           

          Any advice why loadData() gets called multiple times ?

          • 2. Re: How to load rows on demand using rich:scrollabledatatable
            richdeveloper

            Also selection deosn't work....following is the snippet with the selction.....

             

            <rich:scrollableDataTable id="jobListId" value="#{jobScrollableDataModel}" var="jobListRow"

                                        rendered="true" rowClasses="even-row, odd-row" rows="#{configurationManager.maximumJobsInList}" height="400px" selectionMode="single"  rowKey="#{jobListRow.jobId}" rowKeyVar="rkv" ignoreDupResponses="true" style="z-index:-1;width:100%;" selection="#{jobScrollableDataModel.currentSelection}">

             

             

             

            backend bean code:

             

             

            private Selection selection;

              /**

               * @return the selection

               */

              public Selection getCurrentSelection()

              {

                return selection;

              }

             

              /**

               * @param selection the selection to set

               */

              public void setCurrentSelection(Selection selection)

              {

                this.selection = selection;

              }

             

               

              Alert jobAlert;

             

            public String takeSelection() {

              Iterator<Object> iterator = getCurrentSelection().getKeys();

              if(iterator.hasNext()){

                Object key = iterator.next();

                table.setRowKey(key);

                if (table.isRowAvailable()) {

                  table.setRowKey(key);

                  this.setSelectJobRow((JobRow) table.getRowData());

                }

              }

              return null;

            }

            • 3. Re: How to load rows on demand using rich:scrollabledatatable
              richdeveloper

              Ok. Found solution my self :

               

              I needed following to trigger selection: before selection was always null. after supporting following event selction is correct.

               

               

              <a:support event="onselectionchange" action="#{jobScrollableDataModel.takeSelection}" />