Search code examples
javavaadinvaadin8

Vaadin 8 - Sorting items in ComboBox<Integer>


I have a ComboBox of Type Integer that I setup like this:

Collection<Integer> cbItems = new HashSet<>();
for(Integer i = 100; i < 360; i+=5){
    cbItems.add(i);
}
ComboBox<Integer> cb = new ComboBox<>();
cb.setItems(cbItems);

I create a Collection of Integers and fill it with certain Integer values (100, 105, 110, etc...). The Code compiles, and the ComboBox is displayed in the view.

My Problem is that the items in the ComboBox are not sorted (or better: not sorted in the way I thought it would be).

Screenshot of the actual Combobox

Why does it re-sort my Integer-Collection, and how can I prevent it?


Solution

  • I would recommend you to populate components like ComboBox with DataProvider. It will make things easier later.

    Your own solution works fine if there is not added items later to the ComboBox elsewhere. If items are added it might be needed to perform Collections.sort() again.

    With a little change to use DataProvider:

    ListDataProvider<Integer> dp = new ListDataProvider<>(cbItems);
    // the first param is function that returns the value to sort
    // in case of Integer it is that Integer itself.
    dp.setSortOrder(i -> {return i;}, SortDirection.ASCENDING);
    ComboBox<Integer> combo = new ComboBox<>();
    combo.setDataProvider(dp);
    

    Now, if you later add items to combo (through the original Collection):

    // add some items to see where they are sorted
    cbItems.add(102);
    cbItems.add(113);
    

    these items should be sorted to right place in ComboBox.

    Then consider a bit more complex example. If you had a class like:

    @RequiredArgsConstructor
    public class Wrapper {
       @Getter 
       private final Integer id;
       @Getter
       private final String name;
    }
    

    and you wanted to sort it by name descending, it would be like (with test data):

    // generate some dymmy data
    Collection<Wrapper> wrappers = new HashSet<>();
    for(int i=1000; i<=2000; i+=150) {
       wrappers.add(new Wrapper(i, 
               "Rand"+ThreadLocalRandom.current().nextInt(5000, 6000)) );
    }
    
    ListDataProvider<Wrapper> dpWrappers = new ListDataProvider<>(wrappers);
    // now function returns the name of the wrapper to sort as sort argument
    dpWrappers.setSortOrder(wrapper -> {return wrapper.getName();}, 
                                SortDirection.DESCENDING);
    
    ComboBox<Wrapper> comboWrappers = new ComboBox<>();
    comboWrappers.setDataProvider(dpWrappers);
    // remember to set this to have the name of wrapper in combo vaptions
    // instead of the value of  Wrapper.toString();
    comboWrappers.setItemCaptionGenerator( item -> {return item.getName();});