I have an editable combo box in a grid. When a new name is added to the combo box, it becomes part of the list selection for the combo box so it can be selected for other rows.
Here’s the issue, when I add a few rows and enter a name or two and then change rows, the names appears to be copied to other rows. Example - I add 4 rows, then enter John in the third row and Pete in the fourth row. If I alt-tab back up through the rows, John will appear in the third and second row.
Anyone else had a similar problem? I’m guessing the issue is related to not setting the selected combobox value correctly or the editor being in a wierd state.
Source:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.navigator.View;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.SelectionMode;
/**
* This view contains an editable selection list of names and a fixed selection
* list of colors. When new names are typed into the name field, the name will
* become part of the list.
*
*/
@SuppressWarnings("serial")
@SpringView(name = "gridtest")
public class GridTestView extends CssLayout implements View {
Grid<Row> grid = new Grid<Row>();
List<String> colors = Arrays.asList("Red", "Green", "Blue");
List<Row> items = new ArrayList<Row>();
List<Name> names = new ArrayList<Name>();
public GridTestView() {
setSizeFull();
grid.setWidth("300px");
grid.setSelectionMode(SelectionMode.NONE);
addComponent(grid);
Binder<Row> binder = new Binder<Row>();
ComboBox<Name> nameComboBox = createEditableComboBox();
Binding<Row, Name> nameBind = binder.bind(nameComboBox, Row::getName, Row::setName);
Column<Row, String> nameColumn = grid.addColumn(row -> row.getName() != null ? row.getName().getName() : "")
.setCaption("Name");
nameColumn.setEditorBinding(nameBind);
ComboBox<String> colorCombo = new ComboBox<String>("Color", colors);
Binding<Row, String> colorBind = binder.bind(colorCombo, Row::getColor, Row::setColor);
Column<Row, String> colorColumn = grid.addColumn(row -> row.getColor()).setCaption("Color");
colorColumn.setEditorBinding(colorBind);
grid.addItemClickListener(e -> {
int i = items.indexOf(e.getItem());
if (i > -1) {
grid.getEditor().editRow(i);
}
});
grid.getEditor().setBinder(binder);
grid.getEditor().setBuffered(false);
grid.getEditor().setEnabled(true);
Button addRow = new Button("Add Row");
addComponent(addRow);
addRow.addClickListener(e -> {
items.add(new Row());
grid.setItems(items);
});
}
private ComboBox<Name> createEditableComboBox() {
ComboBox<Name> cbx = new ComboBox<Name>();
cbx.setItems(names);
cbx.setItemCaptionGenerator(Name::getName);
cbx.setNewItemHandler(s -> {
// Return if nothing to do.
if (s == null || s.length() == 0)
return;
// trim spaces
s = s.trim();
// Check if we have the entry in the list already. If we do, replace
// the existing's label with our label. This allows a user to modify
// labels, such as john -> John
for (Name n : names) {
if (s.equalsIgnoreCase(n.getName())) {
n.setName(s);
cbx.setSelectedItem(n);
return;
}
}
;
// It didn't exist, create new Name and add it to the
// list of variants
Name n = new Name(s);
names.add(n);
// Update combobox content and set it as the selected value
cbx.setItems(names);
cbx.setSelectedItem(n);
});
return cbx;
}
public class Name {
private String name = null;
public Name(String name) {
setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Row {
Name name = null;
String color = null;
public Row() {
// get next color in the sequence
color = colors.get(items.size() % colors.size());
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
}