I'm developing a Vaadin
app, and I've decided to use the SuggestingComboBox
idea, that allows better searches between items. This works great, but now I can't figure out how to add new elements, that aren't already in the container with the setNewItemHandler
method.
For refference, here is the SuggestingComBox
code:
public class SuggestingComboBox extends ComboBox {
public SuggestingComboBox() {
setItemCaptionMode(ItemCaptionMode.PROPERTY);
setItemCaptionPropertyId("name");
}
@Override
protected Filter buildFilter(String filterString,
FilteringMode filteringMode) {
return new SuggestingContainer.SuggestionFilter(filterString);
}
}
And the SuggestingContainer
code, that comes along the combobox:
public abstract class SuggestingContainer<T> extends BeanItemContainer<T> {
public SuggestingContainer(Class<? super T> type)
throws IllegalArgumentException {
super(type);
}
@Override
protected void addFilter(Filter filter)
throws UnsupportedFilterException {
if(filter instanceof SuggestionFilter) {
SuggestionFilter suggestionFilter = (SuggestionFilter) filter;
filterItems(suggestionFilter.getFilterString());
} else
super.addFilter(filter);
}
//This method is to be overriden
protected abstract void filterItems(String filterString);
public static class SuggestionFilter implements Container.Filter {
private String filterString;
public SuggestionFilter(String filterString) {
this.filterString = filterString;
}
public String getFilterString() {
return filterString;
}
@Override
public boolean passesFilter(Object itemId, Item item)
throws UnsupportedOperationException {
return false;
}
@Override
public boolean appliesToProperty(Object propertyId) {
return false;
}
}
This container is used as this:
public SuggestingField extends CustomField<Model> {
private SuggestingComboBox suggestingCB;
private SuggestingContainer<ObjectItem> container;
public SuggestingField() {
suggestingCB = new SuggestingComboBox();
container = new SuggestingContainer<ObjectItem>(ObjectItem.class) {
@Override
protected void filterItems(String filterString) {
removeAllItems();
List<Model> result; //Obtain here the results
List<ObjectItem> lItems = result.stream()
.map(m -> new ObjectItem(m.getId()+"", m.toString(), m))
.collect(Collectors.toList());
addAll(lItems);
}
};
suggestingCB.setContainerDataSource(container);
suggestingCB.setImmediate(true);
suggestingCB.setItemCaptionPropertyId("text");
}
}
Also, I have a POJO Model
and that ObjectItem
class, that I have to use, beacuse I don't get to work the toString
caption mode.
public class Model {
private int id;
private String name;
//Getters and setters; equals/hash
}
public class ObjectItem {
private String id;
private String text;
private Object o;
//Equals/hash and getters/setters
}
So, my problem is: I'm trying to allow creating new Model
(s) in the field, using the setNewItemHandler
method. This is what I've tried so far.
public SuggestingField extends CustomField<Model> {
...
public void setNewElementsAllowed(boolean allowed) {
this.suggestingCB.setNewItemsAllowed(allowed);
this.suggestingCB.setImmediate(allowed);
if(allowed) {
suggestingCB.setNewItemHandler(caption -> {
Model m = new Model();
m.setNombre(caption);
setValue(m);
});
}
}
public void setValue(Model m) {
super.setValue(m);
if(m == null)
suggestingCB.setValue(null);
else {
ObjectItem it = new ObjectItem(""+m.getId(),
m.getName(), m);
if(container.size() == 0 || !container.containsId(it.getId()))
container.addItem(it);
suggestingCB.setValue(it);
suggestingCB.select(it);
}
}
After debuggind this code, I've found that the newElementHandler
is used, and it adds a new item to the container, but nothing is shown in the ComboBox
and the next handler's execution, the container is empty, as if no item was inserted.
I've been able to identify the error. When you select one item in a ComboBox
, the filterString
becomes ""
, so, if you select something that isn't in the DB, and recall the query, it won't be in the List<Model> result
and thus, it will be unselected.
A way to overcome this is to modify SuggestingField
as here:
public SuggestingField extends CustomField<Model> {
private Model model;
...
public SuggestingField() {
...
container = new SuggestingContainer<ObjectItem>(ObjectItem.class) {
@Override
protected void filterItems(String filterString) {
removeAllItems();
if("".equals(filterString)) {
if(model != null) {
ObjectItem it = new ObjectItem();
it.setId(model.getId()+"");
it.setText(model.toString());
it.setObject(model);
addItem(it);
return;
}
}
List<Model> result; //Obtain here the results
List<ObjectItem> lItems = result.stream()
.map(m -> new ObjectItem(m.getId()+"", m.toString(), m))
.collect(Collectors.toList());
addAll(lItems);
}
};
suggestingCB.addValueChangeListener(ev -> {
this.model = (Model) suggestingCB.getValue();
});
This allows to maintain the new item through filters.