Close
Back

Mission RIP Table: Migrate to Grid! - Components

This is a series of tutorials for upgrading the Table component to Grid.

 

In this post I won’t be able to migrate to an older version of Grid, because adding components inside Grid appeared only with the newly announced version a few weeks ago, so I will jump directly from Table to Grid for Framework 8.1+.

Simple Components

Let’s start by exploring how to add components using the new Grid APIs. Previously it was a tedious operation, looping over the rows and manually adding the components:

  for (int i = 0; i < people.length; i++) {
    TextArea area = new TextArea(null, people[i][1]);
    // Add an item with two components
    Object obj[] = {people[i][0], area, new CheckBox()};
    table.addItem(obj, i);
  }
Also addGeneratedColumn was often used, but now it’s as simple as defining a new column with a specific generator:
  table.addComponentColumn(p -> {
    TextArea area = new TextArea(null, p[1]);
    area.setRows(2);
    return area;
  }).setCaption("Description");

  table.addComponentColumn(p ->
    new CheckBox()).setCaption("Delete");

 

 

We can use addColumn and specific ComponentRenderer, but addComponentColumn is simpler and straightforward API. The result in this specific example is not perfect though, because TextArea has two lines, and it overlaps the default row height provided by the theme. We can have a small workaround like:

  table.setRowHeight(70);
But this won’t work if we don’t know the exact component height beforehand. Also, this increases the header row’s height, since Grid currently does not support variable row height and all rows must have the same height.

 

 

Related commit: Components: To Grid v8.1

Interacting Components

In the previous example, I showed how to add components in Grid, but in this example, let’s see how to interact between components of the same row.

 

The best way of achieving this, is to store information about the components in the data model, for example whether the checkbox is active or not. In my demo and to keep it simple, I will hard code the state into “0” and “1” strings, and manually check them. But normally, in a real application, you should not do that, instead, write getter and setters and appropriate data types:

  {"Galileo", "Liked to go around the Sun", "0"},

 

 

In old code, we had to manually retrieve the other components, use cast, and manipulate them:

  TextArea textArea =
    ((TextArea) table.getContainerProperty(...).getValue());
  textArea.setEnabled(!checkbox.getValue());
We also had to store some kind of identifier to be able to retrieve the corresponding checkbox:
  checkbox.setData(i); // Store item ID
  ...
  Object itemId = checkbox.getData();

 

The strategy with Grid will be a bit different, we decide the state of the TextArea upon rendering it:

  table.addComponentColumn(p -> {
    TextArea area = new TextArea(null, p[1]);
    area.setRows(2);
    area.setEnabled(!p.isActive());
    return area;
  }).setCaption("Description");

 

 

Same for checkbox, and then we add a valueChangeListener that updates the value, and refreshes the row:

  checkbox.addValueChangeListener(evt -> {
    p.setActive(checkbox.getValue());
    table.getDataProvider().refreshItem(p);
  });

 

 

Related commit: Interacting Components: To Grid v8.1

Nested Grids

One famous benchmark, when we mention components in Grid, is how many nested Grids can you make? In this example, we will go one single level of nested Grids, but theoretically you can have unlimited nested Grids.

 

Given the previous examples, nothing new can be expected here. We will use the addComponentColumn API, and adjust the table to look usable in the rows. One of those customizations is adjusting a column width. Previously it was done using PropertyID:

  table.setColumnWidth("Moons", 120);
But in Grid, you do it directly as part of column initialization:
  table.addComponentColumn(p -> {
    ...
  }).setCaption("Moons").setWidth(170);

 

 

Also to hide the header in Table we use:

  moonTable.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
But since Grid supports multiple headers, we need to specify which one to remove:
  moonTable.removeHeaderRow(0);

 

 

Related commit: Nested Tables: To Grid v8.1

Bean Components

In the last example with components of this post, we will cover an interesting use case where the data model is actually defined with components.

 

We will have to explicitly specify the component columns, otherwise Grid will use the toString method of the components:

  table.addComponentColumn(ComponentBean::getTextfield)
          .setCaption("Hello");
  table.addComponentColumn(ComponentBean::getCheckbox)
          .setCaption("There");

 

 

And as usual, we get rid of BeanItemContainer, and instead fill it with setItems directly.

 

Related commit: Bean Components: To Grid v8.1

 

Components are clearly a new concept for Grid, it covers all use cases but I have a feeling that some theming is still needed. We can always use some layouts to fix general cases, or some CSS adjustments in the default theme, especially with regard to default row height and padding. But let’s explore something similar that existed in Grid from day one, in the following section.

Grid Editor

 

Editor appears only per selected row. To enable the editor:

  table.getEditor().setEnabled(true);

 

 

In this example, I found that the less complex way to implement the editor functionalities is to use a proper data model. We no longer need to create a custom TableFieldFactory, in Grid we specify the editor’s component directly during column initialization:

  table.addColumn(Bodies::getName).setCaption("Name")
    .setEditorComponent(nameCb, Bodies::setName);

 

 

Many use cases will find the editor implementation is giving a better user experience and cleaner interface. Non-focused components are rendered as plain text, which makes the UI appear much faster. I’d recommend to use it whenever possible instead of components. We will cover some more editor examples in an upcoming post.

 

Related commit: Grid Editor: To Grid v8

 

How do you find this feature of adding components in Grid? Do you have other use cases?

Comments
Trackback URL:

Add Comment
Please check reported issues for Grid, including #9871
Posted on 9/5/17 4:03 PM.
It's a nice feature request, but I'm not sure when we would see it implemented natively in the Grid. It's also not applicable for the scope of migration from Table to Grid since row editing was not available in Table.

Nevertheless, couple of thoughts were left here: https://github.com/vaadin/framework/issues/9871
Posted on 9/11/17 6:10 PM in reply to Valentin Mocanu.