Search code examples
vaadinvaadin-gridvaadin23

Vaadin 23 Grid: how to sync DataCommunicator with DataProvider?


In a Vaadin 23.3.10 Grid I'd like to select a row that is next to a row that was selected before. Therefore I read the items from the DataCommunicator. Most cases work fine, but the DataCommunicator seems to be not in sync with the DataProvider after calling dataProvider.remove(x) and dataProvider.refreshAll().

The button is plugin-based so the code snippet that selects the next row doesn't know whether some other plugin that ran before removed an item from the grid.

Here is a code example that only shows that a DataProvider and a DataCommunicator are out of sync after removing an item from the DataProvider and that the DataCommunicator is not consistent in its own:

@Route("sandbox")
public class SandboxView extends VerticalLayout {

private class Item {
    String name;
    private Item(String name) {this.name=name;}
}

public SandboxView() {
    // Generate some items
    Item a = new Item("a");
    Item b = new Item("b");
    Item c = new Item("c");
    List<Item> items = new ArrayList<>();
    items.add(a);
    items.add(b);
    items.add(c);
    ListDataProvider<Item> dataProvider = new ListDataProvider<>(items);
    
    // Create a grid
    Grid<Item> grid = new Grid<>();
    grid.setItems(dataProvider);
    grid.addColumn(item -> item.name).setHeader("Name");
    this.add(grid);
    
    // Create a button that removes an item from the grid
    Button button = new Button("Remove item A");
    button.addClickListener(event -> {
            DataCommunicator<Item> dataCommunicator = grid.getDataCommunicator();
            printDataCommunicatorItemInfo(dataCommunicator);
            // Output is as expected:
            // 3 items
            // Item: a
            // Item: b
            // Item: c
            
            dataProvider.getItems().remove(a);
            printDataCommunicatorItemInfo(dataCommunicator);
            // Output is still the same:
            // 3 items
            // Item: a
            // Item: b
            // Item: c
            
            dataProvider.refreshAll();
            printDataCommunicatorItemInfo(dataCommunicator);
            // ## UNEXPECTED ##
            // Output is out of sync:
            // 2 items
            // Item: a
            // Item: b
        }
    );
    this.add(button);
}

private void printDataCommunicatorItemInfo(DataCommunicator<Item> dataCommunicator) {
    System.out.println(dataCommunicator.getItemCount()+" items");
    for (int i=0;i<dataCommunicator.getItemCount();i++) {
        System.out.println("Item: "+dataCommunicator.getItem(i).name);
    }
}

}

The problem is that dataCommunicator.getItemCount() returns the reduced number of items (2) but dataCommunicator.getItem(...) still returns the removed item (a).

Question: How can I force the dataCommunicator to get in sync again?


Solution

  • In Vaadin 23, you can get the next item from the GridListDataView.

    For example:

    GridListDataView<Person> dataView = grid.setItems(DataProvider.ofCollection(PersonUtil.buildPersons())); 
    Person item; // item a 
    Optional<Person> nextItem = dataView.getNextItem(item); dataView.removeItem(item); 
    

    I'm not really sure about the dataCommunicator issue. I didn't look into the issue in details but you don't need to use it.