1 2 3 Previous Next 30 Replies Latest reply on Feb 27, 2012 7:08 AM by martin.hynar

    How do you make rich:datascroller do true pagination?

    rickarcmind

      I have a multi-user webapp that needs a paginateable listing. My goal is to not load the entire listing into session but only the part that the user is actually viewing.

      rich:datascroller seemed like an obvious choice. However, it seems that rich:datascroller expects the entire list to be loaded in memory. Then it calls List.get multiple times.

      Is there a way to change this behavior? The above assumptions are based on the examples in the richfaces-demo.

      Second, if there is no way to do true pagination with rich:datascroller, I by that I mean is there is anyway to not load the entire list into memory and then paginate through the list.

      Third, if you change the code to call List.subList instead of List.get, it would be easier for developers to implement there own DataList (that implements the List interface and provide true pagination) that integrates with rich:datascroller.

      I am certain that this is an oversight on my part and there is another example that shows how to do pagination w/o loading the entire list into memory. Please send me a link or tell me which example to look at.

        • 1. Re: How do you make rich:datascroller do true pagination?
          nbelaevski

          Hello!

          Sorry, I'm not sure that I've got the entire post right... Could you please point to the code in datascroller that queues list for data? (actually, it can, but that's the case when model can't return data set size, so datascroller would determine it using special algorithm).

          You probably should implement your own dataModel extending javax.faces.model.DataModel such that it wouldn't hold all objects in memory.

          We could think on implementing special "batch" model that would be being informed about range of required data by data display component, however it will be incompatible with standard JSF data components, such as h:dataTable.

          • 2. Re: How do you make rich:datascroller do true pagination?
            rickarcmind

            DataModel would not help much. It has no interface that states a contract for paginatable data. It is the current tabular data that is to appear on the screen.

            I don't think this is an edge case. The ability for the control to say, hey I am about to go to the next page, please give items from 50 to 100 is pretty common. When you don't have this capability the short cut is to load a list or a data model that is tied to list into memory, which is the last thing you want JSF developers to do. This does not scale well.

            Do you want everyone who uses your framework to write there own paginatable DataModel (does not seem very productive) or do you want the ability to say give the records from 50 to 100.

            There should be an interface/contract or something that you implement and register with the paginator.

            The smallest change would be to call subList instead of get.

            • 3. Re: How do you make rich:datascroller do true pagination?
              rickarcmind

               

              We could think on implementing special "batch" model that would be being informed about range of required data by data display component, however it will be incompatible with standard JSF data components, such as h:dataTable.


              Standard JSF does not have pagination so you will not be breaking standard JSF pagination by innovating your new stuff.

              • 4. Re: How do you make rich:datascroller do true pagination?
                rickarcmind
                • 5. Re: How do you make rich:datascroller do true pagination?

                  Rick, pls cool down and look what needs to be done. Believe me, this is most obvious use case that was implemented many times by many developers with much less complains.

                  First of all you CAN implement buffered DataModel, all you need to do is a mode to load data in batches as UIData will traverse thought the sequence of rows.

                  But in reality this is a simplistic solution. For sure we can imagine more complex cases, and we did it.

                  You can use a4j:repeat or rich:dataTable to do much more complex things, including easy navigation by pages. Both components are based on org.ajax4jsf.ajax.repeat.UIDataAdaptor, and, therefore, uses much more advanced version of DataModel, that standard DataModel: org.ajax4jsf.ajax.repeat.ExtendedDataModel.

                  http://labs.jboss.com/file-access/default/members/jbossajax4jsf/freezone/docs/apidoc/org/ajax4jsf/ajax/repeat/ExtendedDataModel.html

                  All you need is ? to extends that abstract class and implement it three major methods, as mentioned in Java Doc. So, inside of walk method you have information about range of rows, you can load that rows from Hibernate and call Visitor for every row. At the same time you may address rows by PK, instead of row number (see getRowKey() setRowkey() methods.

                  I recommend you to take a look to default implementation org.ajax4jsf.ajax.repeat.SequenceDataModel which implements all this logic on top of standard javax.faces.model.DataModel.

                  Paginator itself has nothing to do with data loading, it just telling UIData what starting row number it will use.

                  I hope that explanation will help you!


                  • 6. Re: How do you make rich:datascroller do true pagination?
                    rickarcmind

                    [QUOTE]Rick, pls cool down and look what needs to be done. Believe me, this is most obvious use case that was implemented many times by many developers with much less complains. [/QUOTE]

                    I was never heated. Posts don't do well in conveying emotion.

                    [QUOTE]First of all you CAN implement buffered DataModel, all you need to do is a mode to load data in batches as UIData will traverse thought the sequence of rows. [/QUOTE]

                    I COULD drink my own urine, but I do not want to. This seems like a poor design that would rely on a side effect and subterfuge instead of implementing a well-known interface.... he say calmly conveying no emotion....

                    [QUOTE]You can use a4j:repeat or rich:dataTable to do much more complex things, including easy navigation by pages. Both components are based on org.ajax4jsf.ajax.repeat.UIDataAdaptor, and, therefore, uses much more advanced version of DataModel, that standard DataModel: org.ajax4jsf.ajax.repeat.ExtendedDataModel.
                    [/QUOTE]

                    org.ajax4jsf.ajax.repeat.ExtendedDataModel seems like the answer I was looking for. Thanks. I will look into this.

                    • 7. Re: How do you make rich:datascroller do true pagination?
                      rickarcmind

                      I took you adivce and looked at SequenceDataModel, it is not what I expected, but I am sure with a bit of trial and error I could figure it out.

                      It would be nice to see an example of ExtendedDataModel working with Hibernate or JPA.

                      I wrote my own paginator (a while back). The interface conveys what the contract for pagination. It is more similar to what display tag does. Actually I wrote it before and planned on using richfaces to do pagination since it is provided, but alas there are no realistic examples that don't load the entire list into memory and paginate over it.

                      ExtendedDataModel is a bit obtuse if you compare it to what DisplayTag provided. Display Tag API is much more developer (end user developer) friendly.

                      • 8. Re: How do you make rich:datascroller do true pagination?

                        1.) If you like displaytag use it.

                        2.) There is no trivial way to achieve what you want because AFAIK JPA does not have the concept of partially loaded Collections. If it had what about binding it to other data sources. JSF is after all a view technology and waht you talk about is clearly not a part of the view domain. You need a part to convert only that part of the backing list to a datamodel that is supposed to be displayed.

                        So IMHO the datamodel is a cludge that should be used only if GUI concerns require scrolling - not if there is a performance issue.

                        3.)There is a very nice example in the Seam documentation to do real pagination . You'll find it in the section about EntityQueries.

                        Regards

                        Felix

                        • 9. Re: How do you make rich:datascroller do true pagination?
                          wierzba

                          I have the same problem.
                          I use hibernate to load collection of objects but it takes ages, it is possible for me to retrive count of objects before load and then load only a part of it, but still I don't know how to plug it into datascroller+dataTable.
                          Do you have any working code example?
                          Thanks in advance :)

                          • 10. Re: How do you make rich:datascroller do true pagination?
                            rickarcmind

                             

                            1.) If you like displaytag use it.


                            Thanks for your "help". I am comitted to JSF and Ajax4JSF which I will use. I just won't use the richfaces scroller, which does not really scroll.

                            2.) There is no trivial way to achieve what you want because AFAIK JPA does not have the concept of partially loaded Collections. If it had what about binding it to other data sources. JSF is after all a view technology and waht you talk about is clearly not a part of the view domain. You need a part to convert only that part of the backing list to a datamodel that is supposed to be displayed.



                            The API for JPA is fine. It supports pagination fine. Done it before. Got the T-Shirt.

                            So IMHO the datamodel is a cludge that should be used only if GUI concerns require scrolling - not if there is a performance issue.


                            ???

                            3.)There is a very nice example in the Seam documentation to do real pagination . You'll find it in the section about EntityQueries.


                            Yeah. No problem. Pagination with JPA/JSF/Ajax4JSF is not an issue. It has been done several times. It never was an issue for me. The issue was RichFaces DataScroller is non-starter for me. I've already implemented pagination w/o it. I am still using RichFaces. Just not the datrascroller and its obtuse API. Thanks.



                            • 11. Re: How do you make rich:datascroller do true pagination?
                              kewldude

                               

                              "Wierzba" wrote:
                              I have the same problem.
                              I use hibernate to load collection of objects but it takes ages, it is possible for me to retrive count of objects before load and then load only a part of it, but still I don't know how to plug it into datascroller+dataTable.
                              Do you have any working code example?
                              Thanks in advance :)


                              Yeah i hope somebody here can provide some working code example.That will surely go a long way in helping newbies like us.

                              • 12. Re: How do you make rich:datascroller do true pagination?
                                furic

                                Here you are :

                                
                                import java.io.Serializable;
                                import java.util.List;
                                
                                import javax.faces.model.DataModel;
                                
                                public class PagedListDataModel extends DataModel implements Serializable{
                                
                                 private int rowIndex = -1;
                                 private int totalNumRows;
                                 private int pageSize;
                                 private List list;
                                
                                 public PagedListDataModel() {
                                 super();
                                 }
                                
                                 public PagedListDataModel(List list, int totalNumRows, int pageSize) {
                                 super();
                                 setWrappedData(list);
                                 this.totalNumRows = totalNumRows;
                                 this.pageSize = pageSize;
                                 }
                                
                                 public boolean isRowAvailable() {
                                 if(list == null)
                                 return false;
                                
                                 int rowIndex = getRowIndex();
                                 if(rowIndex >=0 && rowIndex < list.size())
                                 return true;
                                 else
                                 return false;
                                 }
                                
                                 public int getRowCount() {
                                 return totalNumRows;
                                 }
                                
                                 public Object getRowData() {
                                 if(list == null)
                                 return null;
                                 else if(!isRowAvailable())
                                 throw new IllegalArgumentException();
                                 else {
                                 int dataIndex = getRowIndex();
                                 return list.get(dataIndex);
                                 }
                                 }
                                
                                 public int getRowIndex() {
                                 return (rowIndex % pageSize);
                                 }
                                
                                 public void setRowIndex(int rowIndex) {
                                 this.rowIndex = rowIndex;
                                 }
                                
                                 public Object getWrappedData() {
                                 return list;
                                 }
                                
                                 public void setWrappedData(Object list) {
                                 this.list = (List) list;
                                 }
                                
                                }
                                

                                in your bean :
                                public UIData getTable() {
                                 return table;
                                 }
                                private DataModel getPagedDataModel(String sortBy){
                                 int totalListSize = getTotalRowsCount();
                                 List pagedList = getPage(table.getFirst(),table.getRows(),sortBy);
                                 PagedListDataModel dataModel = new PagedListDataModel(pagedList, totalListSize, table.getRows());
                                 return dataModel;
                                 }
                                
                                 public DataModel getTableModel() {
                                
                                 return getPagedDataModel(getInitialSortByProperty());
                                 }

                                jsp:
                                <t:dataTable value="#{buildingsBean.tableModel}" var="building" binding="#{buildingsBean.table}"
                                 styleClass="myTable" rows="10" id="buildingsTable">


                                • 13. Re: How do you make rich:datascroller do true pagination?
                                  kewldude

                                  I've just copied the code to my project and I started to plug in the holes needed to make it work. One thing that I've noticed and please correct me if my observation is flawed. Why is the dataScroller is not integrated in your example?
                                  My idea is the dataScroller would be the one to give the value that the dataTable will use in order to get the on demand data from the db. Something like lets say the user clicked page 3....(im using plain sql and not hibernate) and this value will mean that a sub select will be made using oracle's rownum (rownum between 21 and 30)

                                  • 14. Re: How do you make rich:datascroller do true pagination?
                                    furic

                                    Sure, you need datascroller

                                    <t:dataTable value="#{buildingsBean.tableModel}" var="building" binding="#{buildingsBean.table}"
                                     styleClass="myTable" rows="10" id="buildingsTable">
                                    
                                     <f:facet name="footer" >
                                    <rich:datascroller id="paginator" maxPages="10" status="ajaxStatus"
                                    ajaxSingle="false" >
                                    ..facets....
                                    </rich:datascroller>
                                     </f:facet>
                                    </t:dataTable>
                                    


                                    1 2 3 Previous Next