Inserting a button to remove a table row
When we are working with tables, we can use a useful feature for generating columns. In Vaadin, a table is created according to the Container
that is used as a data source. If we use the BeanItemContainer
class, then for each field in the container bean one column is generated. So, if we want to add an other column, we can generate it using the Table.addGeneratedColumn()
method. This generated column exists only in the Table
, not as a property in the underlying Container
. We will use it for generating buttons that remove a current row, as shown in the following screenshot:
How to do it...
Carry out the following steps to learn how to insert a new column in the table:
- We create a Vaadin project with the main UI class called
Demo
as follows:public class Demo extends UI {…}
- Our table will be a list of some products with prices. Therefore, we start with bean
Product
. This bean consists of name and price. We create an appropriate constructor and we also insert getter and setter methods for these variables. We do this as follows:public class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } <insert getter and setter methods for name and price> }
- Now we create our custom component called
PriceList
.public class PriceList extends CustomComponent {…}
- All items will be stored in the container that will be used as a data source of the table. We will use it from the constructor and employ two methods; therefore it will be a global variable. More information about using containers is described in the Binding a container to a component recipe in Chapter 9, Data Management.
private BeanItemContainer<Product> container;
- The constructor will have one parameter:
BeanItemContainer<Product> container
. Through this parameter, we pass the container ofProduct
to the table. Next, we createVerticalLayout
that is used as the main layout for our custom component. We insert a button and table into this layout. The button will be used for adding new items to the container.public PriceList(BeanItemContainer<Product> container) { this.container = container; Table table = createTable(); table.setContainerDataSource(container); VerticalLayout layout = new VerticalLayout(); layout.addComponent(createAddProductButton()); layout.addComponent(table); setCompositionRoot(layout); }
- Next we insert a method that creates the Add product button. It is a simple button with caption Add product and with one
ClickListener
. On the click event, a new instance of theProduct
class will be added to our container.private Button createAddProductButton() { Button addProductButton = new Button("Add product"); addProductButton.addClickListener(new ClickListener() { public void buttonClick(ClickEvent event) { container.addItem(new Product("", 0)); } }); return addProductButton; }
- The table is created in a separate method. As a data source, we set our global container. We want to edit items directly in the table row. So we do it by the
setEditable(true)
method. If the table is editable, an editor of typeField
is created for each table cell.private Table createTable(){ Table table = new Table(); table.setContainerDataSource(container); table.setEditable(true); …
- Next we add our generated column named
Remove
. We create an implementation of theColumnGenerator
interface. In this interface, there is only one method calledgenerateCell()
. This method is called byTable
when a cell in a generated column needs to be generated. In the body of the method, we create a button with caption x and we add a listener in which we remove the item (row in table) with currentitemId
.table.addGeneratedColumn("Remove", new Table.ColumnGenerator() { public Object generateCell( Table source,final Object itemId,Object columnId){ Button removeButton = new Button("x"); removeButton.addClickListener(new ClickListener(){ public void buttonClick(ClickEvent event) { table.removeItem(itemId); } }); return removeButton; } }); return table; }
- That is all. Now we can use our created custom component in the main UI class called
Demo
. Here we insert a method that creates a container ofProduct
with some dummy data.public class Demo extends UI { @Override protected void init(VaadinRequest request) { PriceList priceList = new PriceList(createProductContainer()); setContent(priceList); } private BeanItemContainer<Product> createProductContainer(){ BeanItemContainer<Product> container = new BeanItemContainer<Product>(Product.class); container.addItem(new Product("Computer", 599.90)); container.addItem(new Product("Mobile phone", 14.5)); container.addItem(new Product("Tablet", 99.90)); container.addItem(new Product("Mouse", 0.99)); return container; } }
The application is done. We can run the server and show it in the web browser.
How it works...
We have made a simple custom component that consists of a table and buttons. Columns in a Table
are generated according to fields in the container bean. One button is used for adding new items to the container. Other buttons are placed into the generated column.
Generating the new column is performed by the Table.addGeneratedColumn()
method. A generated column exists only in the Table
. Table
will not listen to value change events from properties overridden by the generated columns. If the content of our generated column depends on properties that are not directly visible in the table, we have to attach a value change listener to update the content on all depended properties. Otherwise, our UI might not get updated as expected.
Also note that the getVisibleColumns()
method will return the generated columns, while getContainerPropertyIds()
will not.
Our generated buttons are used for removing items from the container. Each item is visually represented as a row in the table. So, if the user clicks on the button with caption x, one row is removed.
As a data source, we used the instance of the BeanItemContainer
class, which is a container for JavaBeans. The properties of the container are determined automatically by inspecting the used JavaBean class. Only beans of the same type can be added to the container. In our example, it's Product
type.
See also
- More information about using containers is described in the Binding a container to a component recipe in Chapter 9, Data Management