Vaadin 7.6.2
BeanItemContainer
BeanItemContainer<CountryBean> countryBeanContainer
= new BeanItemContainer<>(CountryBean.class);
countryBeanContainer.addAll(CountryData.list);
country.setContainerDataSource(countryBeanContainer);
country.setItemCaptionMode(AbstractSelect.ItemCaptionMode.PROPERTY);
country.setItemCaptionPropertyId("name");
country.setTextInputAllowed(true);
...
...
CountryBean
public class CountryBean {
private String value;
private String name;
public CountryBean(String value, String name) {
this.value = value;
this.name = name;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
CountryData
public abstract class CountryData {
public static final List<CountryBean> list =
Collections.unmodifiableList(Arrays.asList(
new CountryBean("AF", "Afghanistan"),
new CountryBean("AX", "Ă…land Islands"),
new CountryBean("AL", "Albania"),
new CountryBean("DZ", "Algeria"),
new CountryBean("AS", "American Samoa"),
new CountryBean("AD", "Andorra"),
new CountryBean("AO", "Angola"),
new CountryBean("AI", "Anguilla"),
...
...
So, I have this setup running in a ComboBox and it works great. But my question is: Is this list of 200+ countries compiled into the client side code, or is it lazy loaded from the server as the user types or pages through the list of choices? I would like to understand how this works, because I may need to have (say) 5 country fields in my UI.
ComboBox is handling lazy loading between client side and server out of the box. Only the rows which are visible in the dropdown are fetched from server to client. So when you do filtering or navigate between different pages on the dropdown, it fetches only those rows from the server.
Related
For example in the Select component the selected value is rendered as shown here. However when it comes to the ComboBox it is not rendered, only on the dropdown as shown here. I need to use the ComboBox because I need the search functionality, that is to have the item selected as they type in the value because there may be a lot of values. Ideally it would be great to merge the Select and ComboBox but barring that I'm wondering if there's a way to render the selected value.
You can't use an arbitrary Renderer, because the text input is, well, a text input. As noted in the comments below the question, what you're really after is an icon in front of the value of the input, and while there's no nice API in ComboBox for this, you can frankenstein together a solution using the prefix slot of the vaadin-text-field input. I've adapted an example using the Cookbook recipe here. Note that there's an enhancement request that would make handling prefix/suffix components in ComboBox easier: https://github.com/vaadin/flow-components/issues/1594
public class AboutView extends Div {
public AboutView() {
ComboBox<Person> comboBox = new ComboBox<>();
comboBox.setItems(getPersons());
// Renderer for the drop down
comboBox.setRenderer(new ComponentRenderer<Div, Person>(person -> {
Div container = new Div();
container.add(person.getIcon().create(), new Span(person.getName()));
return container;
}));
// on value change: either clear the prefix slot or create a new Icon there
comboBox.addValueChangeListener(e -> {
Person p = e.getValue();
if (p == null) {
PrefixUtil.clearSlot(comboBox, "prefix");
return;
}
PrefixUtil.setPrefixComponent(comboBox, p.getIcon().create());
});
comboBox.setItemLabelGenerator(Person::getName);
add(comboBox);
}
public List<Person> getPersons() {
List<Person> persons = new ArrayList<>();
Person person1 = new Person("Foo", VaadinIcon.ARROW_BACKWARD);
Person person2 = new Person("Bar", VaadinIcon.BAR_CHART);
Person person3 = new Person("Baz", VaadinIcon.PUZZLE_PIECE);
persons.add(person1);
persons.add(person2);
persons.add(person3);
return persons;
}
public static class Person {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public VaadinIcon getIcon() {
return icon;
}
public void setIcon(VaadinIcon icon) {
this.icon = icon;
}
private VaadinIcon icon;
public Person(String name, VaadinIcon icon) {
this.name = name;
this.icon = icon;
}
}
public static class PrefixUtil {
private static Stream<Element> getElementsInSlot(HasElement target,
String slot) {
return target.getElement().getChildren()
.filter(child -> slot.equals(child.getAttribute("slot")));
}
public static void setPrefixComponent(Component target, Component component) {
clearSlot(target, "prefix");
if (component != null) {
component.getElement().setAttribute("slot", "prefix");
target.getElement().appendChild(component.getElement());
}
}
private static void clearSlot(Component target, String slot) {
getElementsInSlot(target, slot).collect(Collectors.toList())
.forEach(target.getElement()::removeChild);
}
private static Component getChildInSlot(HasElement target, String slot) {
Optional<Element> element = getElementsInSlot(target, slot).findFirst();
if (element.isPresent()) {
return element.get().getComponent().get();
}
return null;
}
public static Component getPrefixComponent(Component target) {
return getChildInSlot(target, "prefix");
}
}
}
I am playing around with vaadin 14.2.2 for testing purpose. However, I got to the first problem using Grid immediately. The Example from https://vaadin.com/docs/v14/flow/components/tutorial-flow-grid.html
List<Person> people = Arrays.asList(
new Person("Nicolaus Copernicus", 1543),
new Person("Galileo Galilei", 1564),
new Person("Johannes Kepler", 1571));
// Create a grid bound to the list
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName).setHeader("Name");
grid.addColumn(Person::getYearOfBirth)
.setHeader("Year of birth");
layout.add(grid);
does not generate an output in the visualization. Also the hint in several GitHub issues to use
grid.setSizeFull();
does not solve this issue.
Has anybody any idea how to solve this?
The following snippet works for me on Vaadin 14.2.2 + Spring:
#Route("MainView")
public class MainView extends VerticalLayout {
public MainView() {
List<Person> people = Arrays.asList(
new Person("Nicolaus Copernicus", 1543),
new Person("Galileo Galilei", 1564),
new Person("Johannes Kepler", 1571));
// Create a grid bound to the list
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName).setHeader("Name");
grid.addColumn(Person::getYearOfBirth).setHeader("Year of birth");
add(grid);
}
class Person {
String name;
Integer yearofbirth;
public Person(String name, Integer yearofbirth) {
this.name = name;
this.yearofbirth = yearofbirth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getYearOfBirth() {
return yearofbirth;
}
public void setYearOfBirth(Integer yearofbirth) {
this.yearofbirth = yearofbirth;
}
}
}
Recently I upgraded Vaadin version for 7 to 8.3.2. One of the changes introduced in newer version is that setContainerDataSource method is deprecated. So I changed my code to:
List<Person> people = Arrays.asList(
new Person("Nicolaus Copernicus", 1543),
new Person("Galileo Galilei", 1564),
new Person("Johannes Kepler", 1571));
// Create a grid bound to the list
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName).setCaption("Name");
grid.addColumn(Person::getBirthyear).setCaption("Year of birth");
Here's Person class implementation:
public class Person implements Serializable {
public Person(String name, int birthyear) {
this.name = name;
this.birthyear = birthyear;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getBirthyear() {
return birthyear;
}
public void setBirthyear(int birthyear) {
this.birthyear = birthyear;
}
private String name;
private int birthyear;
}
Gird is part of HorizontalLayout which is in VerticalLayout.
Unfortunately, in the browser I can see only the border of the table - with no values in it. How can it be so? Am I missing something?
I looked to your code and it seemed to be right, so I copied it to plain Vaadin 8 archetype, and it worked for me. I can see the Grid with right content
Did you remember to recompile the widgetset?
I'm trying to export an Excel corresponding to a FilterTable using Vaadin TableExport. That Filtertable has some columns storing Dates and other class type elements, so I'm using setConverter function to print them as specific Strings:
filerTable.setConverter("dateColumn", dateConverter);
filerTable.setConverter("myClassColumn", myClassConverter);
dateConverter and myClassConverter are instances of some classes to print that column values as Strings.
The problem comes when I want to export the table as an Excel: That setConverter conversions are not being applied to the output file. For example, date cells are being exported as string ('42741,0080787037' instead of '06/01/17 0:11'). The code section to export the Excel file is:
ExcelExport exp = new ExcelExport(new CustomTableHolder(filerTable), "excel.xls");
exp.setRowHeaders(true);
exp.export();
Is there any way to export the table exactly as shown, having applied setConverter function?
Looking at the add-on sources, it seems that this feature is supported but 2 things have to happen in order for it to work:
you have to use a PropertyFormatTable (nothing fancy, just a wrapper over table for this custom purpose)
set the setUseTableFormatPropertyValue(true) on the ExcelExport
Code:
public class ExcelExportTableComponent extends VerticalLayout {
public ExcelExportTableComponent() {
// basic table configuration
Table table = new PropertyFormatTable();
BeanItemContainer<Person> itemContainer = new BeanItemContainer<>(Person.class);
table.setContainerDataSource(itemContainer);
table.setConverter("age", new AgeConverter());
// add some dummy data to the table
Random random = new Random();
for (int i = 0; i < 10; i++) {
itemContainer.addItem(new Person("Name " + i, "Surname " + i, random.nextInt(99) + 1));
}
// add components to the layout
addComponent(table);
addComponent(new Button("Export to excel", event -> {
ExcelExport excelExport = new ExcelExport(table);
excelExport.setUseTableFormatPropertyValue(true);
excelExport.excludeCollapsedColumns();
excelExport.setReportTitle("Demo Report");
excelExport.export();
}));
}
// basic bean for data binding
public static class Person {
private String name;
private String surname;
private int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// custom converter
private static class AgeConverter implements Converter<String, Integer> {
#Override
public Integer convertToModel(String value, Class<? extends Integer> targetType, Locale locale) throws ConversionException {
return Integer.valueOf(value.substring(0, value.indexOf(" years")));
}
#Override
public String convertToPresentation(Integer value, Class<? extends String> targetType, Locale locale) throws ConversionException {
return String.valueOf(value) + " years";
}
#Override
public Class<Integer> getModelType() {
return Integer.class;
}
#Override
public Class<String> getPresentationType() {
return String.class;
}
}
}
Output:
I have an id in the bean and mapped in orm.xml to database. For each id I have to lookup description from database and display. If I have enum values R:"RED" G:"GREEN". Struts does type conversion using EnumConverter. I just want to do similar stuff; if id = 123 what is the product description (lookup). Can I use Struts converter by setting action.properties or by extending StrutsTypeConverter to lookup description for an id = 123? Please let me know if there are any other suggestions.
In short:- Each id I want to lookup description; where description is not part of the bean.
Product Bean
public class Product{
private Long id;
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String planDescription) {
this.description = planDescription;
}
}
Manage Bean
public class Manage{
private Long id;
private String Currency;
..and so on
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
<setters>..<getters>
}
Admin Action uses Manage Bean for all fields on UI
public class ManageAction extends ActionSupport
{
private Collection<Item> allItems;
private Manage manage;
public Collection<Item> getAllItems() {
return allItems;
}
public void setAllItems(Collection<Item> allItems) {
this.allItems = allItems;
}
}
.jsp file action = ManageAction
<s:label key="color" value="#color" />
<s:label key="id" value="%{id}" />
Here the id = 123 and I wish value gets translated to text such as "3IN - 4W - Folded" <product description>
I can have id in the bean always and look up for description each time from a cache and translate and display.
For a enum G:"GREEN" struts conveter gets us G stored in database and GREEN displayed on screen.
similarly if it find id=123 and I wish "write a converter" which looks up in the cache (may be a Map of values) and displays description.