vaadin / flow-components

Java counterpart of Vaadin Web Components
100 stars 66 forks source link

ComboBox with many items does not scroll to correct value #3470

Open mheicke opened 2 years ago

mheicke commented 2 years ago

Description of the bug

We have a ComboBox<ZoneId> to select the users timezone. As you can imagine, there are a LOT of timezones. Lets say the user selects Europe/Kiev and clicks "save", now we store the value for the user. If the user settings screen is opened again, we call comboBox.setValue(user.getTimeZone()) with the Timezone which we saved before. The TimeZone Asia/Tbilisi shows correctly in the ComboBox, but when the dropdown is clicked, the list starts at the top and hasn't scrolled down to Europe/Kiev (see screenshot)

Bildschirmfoto 2022-07-18 um 20 14 23

Expected behavior

I would expect, that if I use comboBox.setValue(xyz), that the element xyz should be scrolled into the visible area. This works on smaller examples, but if you load many items into the ComboBox, it stops to work

Minimal reproducible example

var zoneIds = ZoneId.getAvailableZoneIds().stream()
                    .distinct()
                    .map(ZoneId::of)
                    .collect(Collectors.toList());

timeZone = new ComboBox<>(getTranslation("TimeZone"));
timeZone.setItems(zoneIds);

Versions

rolfsmeds commented 2 years ago

Lazy loading is the cause for this behavior: the selected item is not in the currently loaded "page" of items, and thus cannot be scrolled to. The only way for the Combo Box to be able to scroll to it would be to keep loading more and more pages of items until it encounters the right one to select, which could become a major performance issue with large data sets.

(This is essentially the same reason we haven't been able to provide a scrollToItem method for Grid, and for this issue.)

The default page size for Combo Box is 50 items, but you can override it with e.g. setPageSize(200). (Although you probably want to make sure that whatever page size you set doesn't cause performance issues with slower connections.)

knoobie commented 2 years ago

@rolfsmeds instead of scrolling to the correct item, couldn't this be done like you have suggested for the MSCB (showing selected as first; https://github.com/vaadin/web-components/issues/4185)? This would also allow to have the same UX for CB and MSCB as well.

mheicke commented 2 years ago

@rolfsmeds thanks for the quick answer. Just as idea: we have the full list - lets say 10.000 items. We have the one item, we want to show (number 1530 of the list). Couldn't the combobox show the items 1530 till 1580 and not load the previous once (just show empty elements here, until they are scrolled into view? I guess that would be a rather complicated fix.

I just checked and there are around 600 timezones - do you think that would be an issue for a page size?

TatuLund commented 2 years ago

I just checked and there are around 600 timezones - do you think that would be an issue for a page size?

Yes, I think so. There is limit of 500 items for safety reasons.

rolfsmeds commented 2 years ago

couldn't this be done like you have suggested for the MSCB (showing selected as first; vaadin/web-components#4185)? This would also allow to have the same UX for CB and MSCB as well.

We're considering that, yes, so although that wouldn't really solve the problem per se, it would at least let you find the selected item easily, thus circumventing the problem.

Couldn't the combobox show the items 1530 till 1580 and not load the previous once

I'm not quite sure, but I suspect we'd have the same problem there again: there's no way for the CB to know where in the data the selected item is, so it can't know which page to fetch.

TatuLund commented 1 year ago

One option to workaround is to use Light ComboBox add-on. This component is based on the same web component as the regular ComboBox with the difference that it skips the lazy loading mechanism. Hence scroll to item works. However this component is not suitable for large data sets.

https://vaadin.com/directory/component/light-combobox

See Gist example: https://gist.github.com/TatuLund/c01ffca58869754ea6b419b8c2cbc03b