-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
An IndexOutOfBoundsException is thrown when a grid column is configured as filterable and the grid with GridHelper.setEnhancedSelectionEnabled(grid, true);
The issue occurs when the applied filter results in no matching items, leaving the grid empty after filtering.
Example stacktrace:
java.lang.IndexOutOfBoundsException: Requested index 0 on empty data.
at com.vaadin.flow.data.provider.AbstractListDataView.validateItemIndex(AbstractListDataView.java:297) ~[flow-data-24.5.9.jar:24.5.9]
at com.vaadin.flow.data.provider.AbstractListDataView.getItem(AbstractListDataView.java:82) ~[flow-data-24.5.9.jar:24.5.9]
at com.flowingcode.vaadin.addons.gridhelpers.EnhancedSelectionGridHelper.lambda$enableEnhancedSelection$b9260111$1(EnhancedSelectionGridHelper.java:113) ~[grid-helpers-1.3.2.jar:1.3.2]
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.lambda$fireEvent$2(ElementListenerMap.java:475) ~[flow-server-24.5.9.jar:24.5.9]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.fireEvent(ElementListenerMap.java:475) ~[flow-server-24.5.9.jar:24.5.9]
at com.vaadin.flow.server.communication.rpc.EventRpcHandler.handleNode(EventRpcHandler.java:62) ~[flow-server-24.5.9.jar:24.5.9]
at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:73) ~[flow-server-24.5.9.jar:24.5.9]
at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:550) ~[flow-server-24.5.9.jar:24.5.9]
at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$6(ServerRpcHandler.java:531) ~[flow-server-24.5.9.jar:24.5.9]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
...
Expected behavior
No exceptions should be thrown after filtering and obtaining no results.
Minimal reproducible example
import com.flowingcode.vaadin.addons.gridhelpers.GridHelper;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.Grid.SelectionMode;
import com.vaadin.flow.component.grid.HeaderRow;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.html.NativeLabel;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.textfield.TextFieldVariant;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.List;
import java.util.function.Consumer;
import org.vaadin.lineawesome.LineAwesomeIconUrl;
@PageTitle("Hello World")
@Route("")
@Menu(order = 0, icon = LineAwesomeIconUrl.GLOBE_SOLID)
public class HelloWorldView extends HorizontalLayout {
TextField name;
Grid<Person> grid = new Grid<>(Person.class, false);
public HelloWorldView() {
Grid.Column<Person> nameColumn = grid.addColumn(Person::getFullName);
Grid.Column<Person> emailColumn = grid.addColumn(Person::getEmail);
Grid.Column<Person> professionColumn = grid.addColumn(Person::getProfession);
Grid.Column<Person> docColumn = grid.addColumn(Person::getDocumentNumber);
List<Person> people =
List.of(new Person("Alice Johnson", "alice.johnson@example.com", "Software Engineer", 100000001L),
new Person("Bob Smith", "bob.smith@example.com", "Doctor", 100000002L),
new Person("Charlie Brown", "charlie.brown@example.com", "Teacher", 100000003L),
new Person("David Wilson", "david.wilson@example.com", "Lawyer", 100000004L),
new Person("Emma Davis", "emma.davis@example.com", "Architect", 100000005L),
new Person("Frank Miller", "frank.miller@example.com", "Graphic Designer", 100000006L),
new Person("Grace Lee", "grace.lee@example.com", "Nurse", 100000007L),
new Person("Henry Adams", "henry.adams@example.com", "Mechanical Engineer", 100000008L),
new Person("Isabel White", "isabel.white@example.com", "Journalist", 100000009L),
new Person("Jack Turner", "jack.turner@example.com", "Accountant", 100000010L));
GridListDataView<Person> dataView = grid.setItems(people);
PersonFilter personFilter = new PersonFilter(dataView);
grid.setSelectionMode(SelectionMode.MULTI);
GridHelper.setEnhancedSelectionEnabled(grid, true);
grid.getHeaderRows().clear();
HeaderRow headerRow = grid.appendHeaderRow();
headerRow.getCell(nameColumn).setComponent(createFilterHeader("Name", personFilter::setFullName));
headerRow.getCell(emailColumn).setComponent(createFilterHeader("Email", personFilter::setEmail));
headerRow.getCell(professionColumn).setComponent(createFilterHeader("Profession", personFilter::setProfession));
headerRow.getCell(docColumn).setComponent(createFilterHeader("Profession", personFilter::setDocumentNumber));
add(grid);
}
private static Component createFilterHeader(String labelText, Consumer<String> filterChangeConsumer) {
NativeLabel label = new NativeLabel(labelText);
label.getStyle().set("padding-top", "var(--lumo-space-m)").set("font-size", "var(--lumo-font-size-xs)");
TextField textField = new TextField();
textField.setValueChangeMode(ValueChangeMode.EAGER);
textField.setClearButtonVisible(true);
textField.addThemeVariants(TextFieldVariant.LUMO_SMALL);
textField.setWidthFull();
textField.getStyle().set("max-width", "100%");
textField.addValueChangeListener(e -> {
filterChangeConsumer.accept(e.getValue());
});
VerticalLayout layout = new VerticalLayout(label, textField);
layout.getThemeList().clear();
layout.getThemeList().add("spacing-xs");
return layout;
}
public class Person {
String fullName;
String email;
String profession;
Long documentNumber;
public Person(String fullName, String email, String profession, Long documentNumber) {
this.fullName = fullName;
this.email = email;
this.profession = profession;
this.documentNumber = documentNumber;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public Long getDocumentNumber() {
return documentNumber;
}
public void setDocumentNumber(Long documentNumber) {
this.documentNumber = documentNumber;
}
}
private static class PersonFilter {
private final GridListDataView<Person> dataView;
private String fullName;
private String email;
private String profession;
private Long documentNumber;
public PersonFilter(GridListDataView<Person> dataView) {
this.dataView = dataView;
this.dataView.addFilter(this::test);
}
public void setFullName(String fullName) {
this.fullName = fullName;
this.dataView.refreshAll();
}
public void setDocumentNumber(String documentNumber) {
this.dataView.refreshAll();
if (!documentNumber.isBlank())
this.documentNumber = Long.valueOf(documentNumber);
else
this.documentNumber = null;
}
public void setEmail(String email) {
this.email = email;
this.dataView.refreshAll();
}
public void setProfession(String profession) {
this.profession = profession;
this.dataView.refreshAll();
}
public boolean test(Person person) {
boolean matchesFullName = matches(person.getFullName(), fullName);
boolean matchesEmail = matches(person.getEmail(), email);
boolean matchesProfession = matches(person.getProfession(), profession);
boolean matchesDocumentNumber = matches(person.getDocumentNumber(), documentNumber);
return matchesFullName && matchesEmail && matchesProfession && matchesDocumentNumber;
}
private boolean matches(String value, String searchTerm) {
return searchTerm == null || searchTerm.isEmpty() || value.toLowerCase().contains(searchTerm.toLowerCase());
}
private boolean matches(Long value, Long searchTerm) {
return searchTerm == null || value.toString().contains(searchTerm.toString());
}
}
}
Add-on Version
1.4.1
Vaadin Version
24.6.4
Additional information
No response
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Type
Projects
Status
Done