Unkown Key in Vaadin 14 Grid during selection

460 views Asked by At

I'm using a Grid in Vaadin 14. The grid is in multi-selection mode. The selection handler takes a couple of seconds to complete and I'm calling setItems(...) at the end to update the items in the grid.

When the user selects another row while the previous selection handler is still running, I get an "Unknown key" error similar to the one described in https://github.com/vaadin/vaadin-grid-flow/issues/322, even though the new set of items still contains the selected item (another object instance but same according to equals()). This seems to be because the keys in the KeyMapper have already been changed due to setItems(), so the key coming from the client is not present anymore.

Is there a way to work around this, for example by disabling selection while the previous request is in progress?

UPDATE

To work around this Vaadin bug, I'm also calling setPageSize() with the exact number of items as argument. But it seems the same problem occurs even if I don't call setPageSize(), so it's probably due to setItems().

2

There are 2 answers

8
kscherrer On

Do not change the grids items inside a SelectionListener. You can still do all the things you wanted, but setting the items anew is not actually needed. In fact it will only create problems as you are experiencing now.

While working at this answer, I realized you will need to do your own Checkbox Column in order to be able to do actions for the one item that was just "selected", instead of removing all then add all selected ones (because much better performance). Here is how that could look.

// in my code samples, a `Foo` item can have many `Bar` items. The grid is of type Bar.

Grid.Column customSelectionColumn = grid.addComponentColumn(item -> {
    Checkbox isSelected = new Checkbox();
    isSelected.setValue(someParentFoo.getBars().contains(item));
    isSelected.addValueChangeListener(event -> {
        boolean newSelectedValue = event.getValue();
        if(newSelectedValue){
            someParentFoo.getBars().add(item)
        } else {
            someParentFoo.getBars().remove(item);
        } 
        fooRepository.save(someParentFoo);
    });
});
// make a Checkbox that selects all in the header
Checkbox toggleSelectAll = new Checkbox();
toggleSelectAll.addValueChangeListener(event -> {
    if(event.getValue()){
        someParentFoo.getBars().addAll(allGridItems);
    } else {
        someParentFoo.getBars().removeAll(allGridItems);
    }
    fooRepository.save(someParentFoo);
    grid.getDataProvider().refreshAll(); // updates custom checkbox value of each item
});
gridHeaderRow.getCell(customSelectionColumn).setComponent(toggleSelectAll);
1
Vasily Menshev On

I solved this problem. Vaadin use data as key in HashMap. You need calc hashCode use immutable data fields. For example

public class TestData {

    private int id;
    private String name;

    public TestData(int id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}