I’m just doing a bit of R&D, looking at using Vaadin for a new project; we’ll be using Hibernate + Spring, and the DB access will be through DAO objects.
Now, I’ve had a look at the Incubator HbnContainer, but for our purposes I want to stick to using DAOs - and I also need to have “lazy-loading” of tables - i.e. what would be “paging” in a non-ajax environment; clearly, I needed to implement a new container.
I suspect that this may be a common usecase, especially if/when Vaadin grows in popularity.
After a few false starts, and a couple of hours of getting it wrong, it struck me that the “itemId” of an Item can simply be the Row Number; i.e. the relative index number of the record in the resulting query. This was one of those “lightbulb” moments - the BeanItemContainer’s use of the bean as the itemId had really thrown me!
Anyway, I’ve implemented an AbstractRowContainer that implements everything (on Container.Indexed), except Item getItem(Object itemId), leaving the actual management/retrieval of the rows to a subclass; I am in the process of doing the slightly tricker “page management” in an implementation of the abstract class.
I just thought it was worth mentioning for any other new users (itemId can simply be row number), and to suggest that the chapter on Data Binding could perhaps be expanded a little to discuss how the components and containers interact (I’m still finding things out by trial and error). Let me say, though, that it is great to see a framework such as this with good documentation!
Hi there! There have been quite a few requests of a lazy loading container, and it would be nice to get into the package or as an extra downloadable feature. Some of us are trying to push forward the use of
Uservoice , where anyone can request and vote about new features. I did a
feature request on this, and if you would like to see this in Vaadin, vote for it. Go ahead and come up with new feature requests too!
As a side not, you can easily do your own paging implementation to the table if you want that. You’ll lose the nice scrolling feature of the table, but you can easily handle how the table loads up the items.
Here’s a little proof of concept i did - it only loads up the twenty objects that are visible at the moment.
As I mentioned, I’ve implemented an AbstractRowContainer which leaves a subclass to just implement getItem(Object itemId); I’ve also implemented a (very much work in progress) subclass that uses a pre-existing paged DAO to get the data, by working out which page the item is on, and if that page is not loaded, loading it, then returning the appropriate item.
This is all very “cool-and-froody”, to quote one Zaphod Beeblebrox; I get the server-side concerns of lazy loading, with all the UI goodness of a scrollable table with no next/previous buttons.
However, it does leave me with “empty spaces”, when the user scrolls below or above the current page, until the server “catches up”.
So, I’ve tried to be a bit smart, following the hints and suggestions made by Henry in
this thread ; let’s say I have a page size of 100 items, and an arbritrarily high number of pages. Instead of just loading one page, I try and load three - previous, current and next. When I get within say 20 rows of the end of the current page, I try and load the next page, and drop the earliest page - and the same when I get within 20 rows of the beginning of the current page, I try and load the previous page, and drop the last page.
This is “almost” right - however, the table component often seems to ask for id’s of rows significantly earlier than the first row visible, so I am getting a lot of “churning” of pages, which leaves with blank spaces on the table again (until the server finished loading).
The table uses functions like getItem etc to fetch items from the container. How about just keeping a list of fetched items in the container, and whenever the table asks for an item that isn’t in the container, you’ll load up like a hundred more items just around that id? in Pseudocode it is about this: 1. getItem: check if the item is in the container. 2. if it is not, fetch more items. 3. call super.getItem to get the item and show it.
(We use IntelliJ Idea, hence the slightly different project structure)
If you start the app, and watch stderr, when you first load the table, two pages are loaded. As you scroll down, again, sometimes several pages are loaded - this is reflected by the vaadin activity indicator - often it’ll go yellow, and sometimes red as multiple pages are being loaded (possibly unecessarily)
OK - will do, although as I see it, there are are issues here. The table component appears to ask for a load of items from the container that are far outside the currently visible rows.
In my browser, I suppose I can see around 25 rows. I have set the example up with a page size of 100 rows - yet when the table is first shown, it asks for both pages 1 AND 2.
Not sure quite where to go with it - hence my looking at “manual” paging…
The table component renders some “cache” above and below the visible area. We are doing this to make scrolling as smooth as possible, but still using a moderate amount of resources in both client and server side. The “caching rate” by default is two times the page length. So if your pagelength is 25 and you scroll on to a completely new area, 25 + 2X2x25 rows will be requested from your container. Then in Vaadin table you can scroll between two “pages”.
I hope this clarifies the mysterious scrolling table in Vaadin a bit.
I have just run into the same issue investigating Vaadin.
Charles, are you actively working on this?
I got the sources off the incubator and have started adding more abstraction layers to the Container hierarchy. Interested in enhancing this together…?
First of all I made another abstract class that handles the paging mechanism, so that the concrete classes simply needs to implement calculateNumberOfRows() and loadPage().
However I see a need to be able to initialize the container after it has been constructed (mostly due to IoC/DI issues). Preferrably it would be automatically initialized when accessed, so I’m thinking this could go in the AbstractRowContainer. For example making numberOfRows an Integer that is null until initialization? Should I create such a patch? 11239.html (1.77 KB)
It would be nice to have some abstract class in Vaadin Core. I would suggest to rename
AbstractRowContainer to
AbstractReadOnlyRowContainer – it speaks better for this name.
Mattias , I cannot completely agree with implementation of
AbstractPagingContainer you suggest: the meaning of what
page should be somehow be in sync with
Table . With pre- and post- visible items fetching I believe that on page boundaries this class may cause page number
N-1 ,
N ,
N+1 requested and then again
N on next table redraw. Am I right? In this case I believe,
LRUMap is better then
List .
This was too long ago for me to remember (haven’t used Vaadin since), but I believe you have to avoid confusing the page size of the container with the number of items visible in the GUI (such as rows in a table). As you are mentioning, the page size should be at least 3 x the visible size.
Mattias , thank you for your reply. After thinking and playing around I have come up with yet another solution for the containers. Maybe it will be useful for somebody else. If somebody wishes to see the source code in Vaadin’s incubator – let me know.
I have started from the idea, that in most cases containers that holds information from DB (or any other external source) are ReadOnly. Then I came up to idea, that information coming from the DB can be of two types:
With natural ID, that identifies the item uniquely. This is the most common case.
With no ID. In this case we can introduce the “surrogate” ID, which is simply a item sequence number, as it was returned from DB. For example, some search engine returns you some set of information, sorted by relevance.
For that purposes I’ve created two classes:
IdReadOnlyContainer and
SurrogateIdReadOnlyContainer . As they are read-only, they have no listener notification support for container resizing and property changes.
Then I have introduced the concept of
FetchItemStrategy : this is something, which actually performs fetching the information from DB (or any other remote provider). I have implemented two basic strategies:
AbstractIdPageFetchItemStrategy , that allows to you fetch information in bulks
AbstractLRUFetchItemStrategy , that uses LRU map as a caching backend
Separation of the strategies from container logic allows to replace them with minor efforts. In my case I instantiate the strategies in Spring context and wire them with service providers. 11489.zip (20 KB)