Reputation: 21
I would like to dynamically populate a combobox from Vaadin7 using a rest API. The API returns a lot of values if not filtered.
This is the basic idea I have. I know that the version of Vaadin contains better ways to bind data but I need to use this is a new-old legacy system.
My main problem is that the event does not fire when typing new values and also I am not sure how to get the current value in the combobox so I can send it as a filter to the API
Here is the code
@SpringUI
public class MainView extends UI {
@Autowired
private NameService nameService;
private ComboBox comboBox;
@Override
protected void init(VaadinRequest request) {
VerticalLayout verticalLayout = new VerticalLayout();
comboBox = new ComboBox();
comboBox.setContainerDataSource(getDataSource());
comboBox.setItemCaptionMode(ItemCaptionMode.PROPERTY);
comboBox.setItemCaptionPropertyId("name");
comboBox.setImmediate(true);
comboBox.addValueChangeListener(event -> {
// When I manually enter a property I want to go to the server
// Rest API and get a new List of names
String filter = event.getProperty().toString();
comboBox.setContainerDataSource(getDataSourceWithFilter(filter));
}
);
verticalLayout.addComponent(comboBox);
setContent(verticalLayout);
}
// Get 20 names with a filter
private BeanContainer<String, Name> getDataSourceWithFilter(String filter) {
BeanContainer<String, Name> container = new BeanContainer<>(Name.class);
container.setBeanIdResolver(Name::getId);
// this list comes from a webservice API
List<Name> names = nameService.fetch(filter, 0, 20).collect(Collectors.toList());
container.addAll(names);
return container;
}
// Get 20 (default) names without filtering
private BeanContainer<String, Name> getDataSource() {
return getDataSourceWithFilter("");
}
}
Upvotes: 1
Views: 143
Reputation: 21
I have found the solution by creating my own Combobox and overriding the changeVariables method. Thanks to all of you who pointed me to the right direction.
So it looks like this:
public class FilteringComboBox extends ComboBox {
@Override
public void changeVariables(Object source, Map<String, Object> variables) {
if (variables.containsKey("filter")) {
final String text = variables.get("filter").toString();
fireEvent(new TextChangeEvent(this) {
@Override
public String getText() {
return text;
}
@Override
public int getCursorPosition() {
return text.length();
}
});
}
super.changeVariables(source, variables);
}
public void addTextChangeListener(TextChangeListener listener) {
addListener(TextChangeListener.EVENT_ID, TextChangeEvent.class, listener, TextChangeListener.EVENT_METHOD);
}
public void removeTextChangeListener(TextChangeListener listener) {
removeListener(TextChangeListener.EVENT_ID, TextChangeEvent.class, listener);
}
}
And then I used it in the main UI as follows:
@SpringUI
public class MainView extends UI {
@Autowired
private NameService nameService;
private FilteringComboBox comboBox;
@Override
protected void init(VaadinRequest request) {
VerticalLayout verticalLayout = new VerticalLayout();
comboBox = new FilteringComboBox();
comboBox.setContainerDataSource(getDataSource(""));
comboBox.setItemCaptionMode(ItemCaptionMode.PROPERTY);
comboBox.setItemCaptionPropertyId("name");
comboBox.setImmediate(true);
comboBox.addTextChangeListener(event -> {
String filter = event.getText();
comboBox.setContainerDataSource(getDataSource(filter));
}
);
verticalLayout.addComponent(comboBox);
setContent(verticalLayout);
}
private BeanContainer<String, Name> getDataSource(String filter) {
BeanContainer<String, Name> container = new BeanContainer<>(Name.class);
container.setBeanIdResolver(Name::getId);
List<Name> names = nameService.fetch(filter, 0, 20).collect(Collectors.toList());
container.addAll(names);
return container;
}
}
Upvotes: 1