flow: Grid pagination broken when using count

Description of the bug

If a count is used in the grid.setItems call, such as the following code: grid.setItems(query -> samplePersonService.list( PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query))) .stream(), query -> samplePersonService.count());

Then the pagination that Vaadin creates gets confused for the last page if the number of items to be fetched is not a multiple of the page size (50 by default).

What ends up happening is that the last few items (depending on the item count and page size) are duplicates of the preceding items.

The following example is based on what gets produced by start.vaadin.com with the helloworld page changed to a Master-Detail view. Additional lines are added to data.sql to make the record count not be a multiple of 50.

Example original code (count is commented out): grid.setItems(query -> samplePersonService.list( PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query))) .stream()/*, query -> samplePersonService.count()*/);

Result: image

Note that the lines at the bottom contain the additional people added to data.sql.

With the following code (count is enabled): grid.setItems(query -> samplePersonService.list( PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query))) .stream(), query -> samplePersonService.count());

Result: image

Note that the last few lines are duplicated instead of showing the correct data.

Please note that this seems to be dependent on the user scrolling using the mouse rather than going to the bottom of the grid at once using the scroll bars.

Expected behavior

The resulting grid data should not depend on the whether the code makes use of the record count or if the user scrolls with the mouse, or the scroll bars or goes directly to the end of the grid. The results should be the same.

Minimal reproducible example

Steps to duplicate:

  • Go to start.vaadin.com and change the hello world page to use a Master-Detail view.
  • Download the resulting zip file, open in the IDE, get it to run, etc.
  • Add 13 additional lines to the data.sql file so the record count doesn’t match a multiple of the page size.
  • Change the code for grid.setItems in HelloWorldView.java to: grid.setItems(query -> samplePersonService.list( PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query))) .stream(), query -> samplePersonService.count());
  • Run the application and scroll with the mouse wheel towards the end of the grid to see the duplicated items.

Attached is a zip file with the steps above in case I have missed anything. my-app.zip

Versions

  • Vaadin / Flow version: 23 and 24
  • Java version: 11 and 17
  • OS version: Linux
  • Browser version (if applicable): N/A
  • Application Server (if applicable): N/A
  • IDE (if applicable): N/A

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Reactions: 5
  • Comments: 29 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Tbh. This must be resolved asap, because filtering is pretty annoying without setDataProvider, I was using configurable data provider, but with setItems handling filter and sorting is not really intuitive.

Exact same issue, have you find any solution?

@caalador Updated to 24.2.1 and everything works as expected. Thanks for the fix!

@rsercano we are planning to release next Vaadin 24.1 release today, so hopefully it will be available in maven tomorrow.

Noted that the data offset becomes wrong after fast scroll when scrolling backwards.

The issue is the page count that depends on a limit when count is invoked making the page calculation wrong if it’s not a integer match in length. So Now that the end result is 13 there is a calculation that we should get the items from after page 7 for page size 13 which is not 100 and thus we start 13 items from item 92 as 7*13=91

I have the same issue when using

var configurableFilterDataProvider = DataProvider.fromFilteringCallbacks(
        fetchCallback, countCallback).withConfigurableFilter();

IMO, this is a severe error as it produces wrong results and should be fixed ASAP

This must be labeled as criticial IMHO. It’s pretty annoying.