3

I am wondering how I can update a component in Vaadin when mutating data from an event listener. The code in question looks like this:

Set<Long> identifiers = new LinkedHashSet<>();

Grid<Long> grid = new Grid<>(Long.class);
grid.addColumn((ValueProvider<Long, Long>) value -> value);
grid.setDataProvider(new ListDataProvider<>(identifiers));

TextField identifier = new TextField();
identifier.getElement().addEventListener("keyup", event -> {
  String value = event.getEventData().getString("element.value");
  if (value != null && value.length() > 0) {
    try {
      identifiers.add(Long.parseLong(value));
      identifier.clear();
    } catch (NumberFormatException e) {
      Notification.show("Not a valid identifier: " + value);
    }
  }
}).addEventData("element.value").setFilter("event.key == 'Enter'");

The event is dispatched just as I expect it, but the grid is not rerendered in the user view. How do I tell Vaadin that the grid needs rerendering from the event handler?

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192

1 Answers1

3

Re-rendering the grid is done by refreshing the DataProvider. You can do this like so:

grid.getDataProvider().refreshAll();

Edit: my explanation was based on wrong assumptions

The ListDataProvider does not copy the collection supplied to it, so changing the original item collection will affect the data provider. But it does not re render itself automatically, you still have to call refreshAll().

refreshAll() will basically reiterate over the data providers items, rebuild the rows, and reapply any custom column definitions (i.e. styleGenerators and other state-based decisions). As long as you keep the original collection up to date with what you want to show, calling refreshAll() should work.

If you want to completely change the shown item list, you can either remove all items from the original collection (identifiers) and add new items to it, then refresh all, or you can then simply set a new data provider with a new item collection.
(This line would solve OP's problem as well, but should be avoided if refreshAll suffices.)

grid.setDataProvider(new ListDataProvider<>(otherIdentifiers));
kscherrer
  • 5,486
  • 2
  • 19
  • 59
  • In fact, while writing this, I became unsure if `refreshAll()` would work after all, even showing the freshly added item. Could anyone kindly assert this statement for me? – kscherrer May 02 '19 at 15:59
  • I just tested it and you are perfectly correct. Thanks for your help! – Rafael Winterhalter May 02 '19 at 16:52
  • 1
    Yes, the `refreshAll()` should work. `ListDataProvider` does not copy the collection supplied to it, but uses the same object reference. So editing the original reference edits the underlying collection in the `ListDataProvider`. – Erik Lumme May 03 '19 at 05:15
  • `ListDataProvider does not copy the collection supplied to it, but uses the same object reference. So editing the original reference edits the underlying collection in the ListDataProvider`but doesn't that mean that the last part of the accepted answer is wrong? If ListDataProvider doesn't work with a copy of the list but with the same reference you don't have to re-set the DataProvider when adding/removing items, right? – codinghaus May 03 '19 at 05:19
  • 1
    @codinghaus my last part of the answer is directly contradicting this statement. Re-setting the data provider would only be needed if the data provider worked with a copy of the item list, which apparently is not the case. calling `refreshAll()` shold be enough for OP. I will edit my answer shortly to reflect that. – kscherrer May 03 '19 at 07:12