Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
V8 ComboBox value set
I have two related (bound) comboboxes, A and B. A has a ValueChangeListener that fetches the items and sets the default for B. The problem is that if the item list for B is empty and I try to setValue(null) in order to reset the previous value it still sticks around and is visible in B. B allows null values and I tried various other setSelected/reset on B but the previous selection is still not cleared. Any pointers?
It would be helpful if you shared some code, particularly the classes that you are using as the generic types for A and B.
In any case, I've worked up a simple example that shows how to use V8 ComboBox with a basic String as well as a custom class. In short, if you have a custom class for B, you should create an instance that returns the empty string from its toString() method, or whatever method you may have passed to .setItemCaptionGenerator() on ComboxBox B. If you are using String as the generic type for B, just pass the empty string.
public class MyUI extends UI {
private static class StringWrapper {
private final String string;
public StringWrapper(String string) { this.string = string; }
@Override public String toString() { return string; }
public static final StringWrapper EMPTY = new StringWrapper("");
}
private final HashMap<String, List<String>> data1 =
new HashMap<String, List<String>>() {{
put("A", Arrays.asList("A1", "A2", "A3"));
put("B", Arrays.asList("B1", "B2", "B3"));
put("C", Arrays.asList("C1", "C2", "C3"));
put("D", Arrays.asList());
}};
private final HashMap<String, List<StringWrapper>> data2 =
new HashMap<String, List<StringWrapper>>() {{
put("A", Arrays.asList(new StringWrapper("A1"), new StringWrapper("A2"), new StringWrapper("A3")));
put("B", Arrays.asList(new StringWrapper("B1"), new StringWrapper("B2"), new StringWrapper("B3")));
put("C", Arrays.asList(new StringWrapper("C1"), new StringWrapper("C2"), new StringWrapper("C3")));
put("D", Arrays.asList());
}};
@Override protected void init(VaadinRequest vaadinRequest) {
final HorizontalLayout boxLayout = new HorizontalLayout();
setContent(boxLayout);
final ComboBox<String> box1 = new ComboBox<String>();
final ComboBox<String> box2 = new ComboBox<String>();
final ComboBox<StringWrapper> box3 = new ComboBox<StringWrapper>();
boxLayout.addComponents(box1, box2, box3);
box1.addValueChangeListener(event -> {
// Swap out values for box2 based on what's selected in box1
List<String> items = data1.get(box1.getValue());
box2.setItems(items);
box2.setSelectedItem(items.stream().findFirst().orElse(""));
});
box1.addValueChangeListener(event -> {
/*
* Swap out values for box3 based on what's selected in box1. Here we
* use a custom class and a static instance whose toString() returns
* the empty string.
*/
List<StringWrapper> items = data2.get(box1.getValue());
box3.setItems(items);
box3.setSelectedItem(items.stream().findFirst().orElse(StringWrapper.EMPTY));
});
Set<String> items = data1.keySet();
box1.setItems(items);
box1.setSelectedItem(items.stream().findFirst().get());
box1.setEmptySelectionAllowed(false);
}
@WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet extends VaadinServlet {}
}
Ah, I think I see the problem now - thanks for your time. There is no longer some sort of
setNullSelectionItemId in V8?
Nicklas,
That is correct: setNullSelectionItemId() came from the AbstractSelect class, which has been replaced by the AbstractSingleSelect<T> class. Data binding in V8 was completely overhauled to use generics for type safety and better run-time performance. That is why ComboBox is now ComboBox<T>, as with other selection components. In V8, you can specify which method on your class T returns a caption string to be displayed by the selection component by using .setItemCaptionGenerator(). The default is simply to call .toString() on the object. Thus, you can get the same effect by simply having an object that returns the empty string from its caption method, without having to explicitly use null.
This approach is not necessarily the only -- or best -- way to do it, but it's the most similar to the setNull... approach from V7, in which you explicitly designate an object to mean "empty". Take a look at the HasValue interface (docs), which is implemented by selection components. In particular, look at the getOptionalValue() method, which uses java.util.Optional<T>.
-- AC
Kind of interesting that there is a
https://vaadin.com/api/8.0.4/com/vaadin/data/HasValue.html#getEmptyValue--
I don't remember for sure but I have a feeling that having a null object with the ""-toString also interfers with a required-validation-check so that it's actually considered a value(?)
Hey, the binder has a withNullRepresentation that looks promising!