Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
Paging ComboBox with external service
I am trying to create a ComboBox which uses an external service call to populate the container. The service may return many results and has the ability to page results given the id of the last retrieved item. Say I want to make the ComboBox show 50 results at a time and when the user scrolls down past the last (i.e. 50th) item in the dropdown, it will trigger a call to the external service which will return the next 50 items and I can add it to the list of items in the container?
I have managed to create my own container and filter such that the container's addFilter(Filter) method is triggered every time the user moves pages in the combobox's dropdown. However, I can't distinguish between whether the user is moving forwards or backwards in the list of pages and whether the user is looking at the last page and therefore I should make a call to the external service to retrieve the next set of results to append to the list of items.
I feel as though I'm going the long way around to acheiving what I want. Could someone provide any suggestions?
from what you have written, ComboBox may not be the right tool for your needs, as you probably don't want a ComboBox with more than 50 entries in your UI. Have you considered displaying the items in a grid? There you would have proper paging out-of-the-box.
The Viritin addon has a selection of useful bits and pieces.
One of them is a LazyComboBox that provides paging; here is an example of usage.
(Matti Tahvonen is the author, I'm just a happy user!)
Thanks for the ideas guys.
I had a closer look at the Virtin addon which gave me the idea of creating a custom container that only loaded the first 10 results while the remaining, let's say, 90 results are populated using empty beans which are resolved when the user pages through the results.
Only thing is, I would need to know that there are 100 possible results which would tell the Combobox that paging is required. Any ideas on how to load just the first 10 results and somehow allow the user to trigger an attempt to fetch the next 10 results (assuming there is 10 more)? i.e. the combobox initially thinks there are only 10 results but there could be more.
I'm pretty sure this is stretching its capabilities and that it needs to know beforehand that there are 100 total results to lazily load into the dropdown.
That's pretty much what the LazyComboBox is, isn't it? By using this constructor, you can tell it how to get the data, and also how many rows it has; it'll only load the page of data when it's needed for display (+- a page or two, for buffering purporses) - i.e. when the user scrolls through the results.,
My implementation is probably similar to the Viritin one you mentioned with a few unique differences to cater for the scenarios I'm dealing with.
The only issue I have now is that in my solution (as well as the Viritin one) is that there is a need to know the total count ahead of time. In my situation you won't know what the total/final count will be - I've currently just hard coded a total count number for now so I can test that the lazy loading works.
What I've done currently is:
* call the server to read the first 20 results
* only add the first 10 results to the combobox
* since I know whether or not there are more than 10 results, I can add an extra 'empty' 10 items to the combobox
* so now when you first use the combobox, it will say it has results 1-10/20
What I want to do now is that when you page to the second page, it will get the next 10 results (which i know exist) along with the next 10 (if there are any more). If there are more than 20 results, I will again create another 10 empty items in the container so that it will read "11-20/30".
Only problem is that I'm trying to add the new empty items in the "getItemIds(int startIndex, int numberOfIds)" method which is called by the component's "paintContent" method. When I try and call "addItem" inside "getItemIds" I get the exception of:
[com.vaadin.server.DefaultErrorHandler] (default task-11) : java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231) [rt.jar:1.8.0_65]
at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091) [rt.jar:1.8.0_65]
at java.util.AbstractList.listIterator(AbstractList.java:299) [rt.jar:1.8.0_65]
at java.util.ArrayList$SubList.iterator(ArrayList.java:1087) [rt.jar:1.8.0_65]
So essentially I'm trying to find a hook where I can safely add new items to the container after the user has gone to the next page of results.
All good. Figured it out.
I no longer create empty applications. I overrode the size() method to trick the combobox into thinking there are more items in the container.
I also eagerly retrieve additional results in the getItemIds() method that I overrode so that I know how many items exist in the next page and then use that with some extra logic in size() to continuosly update the size() method to ensure paging keeps ticking over as the user pages through the results.