Thanks, we value your feedback!

5.21. Table

The Table component is intended for presenting tabular data organized in rows and columns. The Table is one of the most versatile components in Vaadin. Table cells can include text or arbitrary UI components. You can easily implement editing of the table data, for example clicking on a cell could change it to a text field for editing.

The data contained in a Table is managed using the Data Model of Vaadin (see Chapter 8, Binding Components to Data), through the Container interface of the Table. This makes it possible to bind a table directly to a data source, such as a database query. Only the visible part of the table is loaded into the browser and moving the visible window with the scrollbar loads content from the server. While the data is being loaded, a tooltip will be displayed that shows the current range and total number of items in the table. The rows of the table are items in the container and the columns are properties. Each table row (item) is identified with an item identifier (IID), and each column (property) with a property identifier (PID).

When creating a table, you first need to define columns with addContainerProperty(). This method comes in two flavors. The simpler one takes the property ID of the column and uses it also as the caption of the column. The more complex one allows differing PID and header for the column. This may make, for example, internationalization of table headers easier, because if a PID is internationalized, the internationalization has to be used everywhere where the PID is used. The complex form of the method also allows defining an icon for the column from a resource. The "default value" parameter is used when new properties (columns) are added to the table, to fill in the missing values. (This default has no meaning in the usual case, such as below, where we add items after defining the properties.)

Table table = new Table("The Brightest Stars");

// Define two columns for the built-in container
table.addContainerProperty("Name", String.class, null);
table.addContainerProperty("Mag",  Float.class, null);

// Add a row the hard way
Object newItemId = table.addItem();
Item row1 = table.getItem(newItemId);
row1.getItemProperty("Name").setValue("Sirius");
row1.getItemProperty("Mag").setValue(-1.46f);

// Add a few other rows using shorthand addItem()
table.addItem(new Object[]{"Canopus",        -0.72f}, 2);
table.addItem(new Object[]{"Arcturus",       -0.04f}, 3);
table.addItem(new Object[]{"Alpha Centauri", -0.01f}, 4);

// Show exactly the currently contained rows (items)
table.setPageLength(table.size());

In this example, we used an increasing Integer object as the Item Identifier, given as the second parameter to addItem(). The actual rows are given simply as object arrays, in the same order in which the properties were added. The objects must be of the correct class, as defined in the addContainerProperty() calls.

Figure 5.43. Basic Table Example

Basic Table Example

Scalability of the Table is largely dictated by the container. The default IndexedContainer is relatively heavy and can cause scalability problems, for example, when updating the values. Use of an optimized application-specific container is recommended. Table does not have a limit for the number of items and is just as fast with hundreds of thousands of items as with just a few. With the current implementation of scrolling, there is a limit of around 500 000 rows, depending on the browser and the pixel height of rows.

Common selection component features are described in Section 5.5, “Selection Components”.

5.21.1. Selecting Items in a Table

The Table allows selecting one or more items by clicking them with the mouse. When the user selects an item, the IID of the item will be set as the property of the table and a ValueChangeEvent is triggered. To enable selection, you need to set the table selectable. You will also need to set it as immediate in most cases, as we do below, because without it, the change in the property will not be communicated immediately to the server.

The following example shows how to enable the selection of items in a Table and how to handle ValueChangeEvent events that are caused by changes in selection. You need to handle the event with the valueChange() method of the Property.ValueChangeListener interface.

// Allow selecting items from the table.
table.setSelectable(true);

// Send changes in selection immediately to server.
table.setImmediate(true);

// Shows feedback from selection.
final Label current = new Label("Selected: -");

// Handle selection change.
table.addValueChangeListener(new Property.ValueChangeListener() {
    public void valueChange(ValueChangeEvent event) {
        current.setValue("Selected: " + table.getValue());
    }
});

Figure 5.44. Table Selection Example

Table Selection Example

If the user clicks on an already selected item, the selection will deselected and the table property will have null value. You can disable this behaviour by setting setNullSelectionAllowed(false) for the table.

The selection is the value of the table's property, so you can get it with getValue(). You can get it also from a reference to the table itself. In single selection mode, the value is the item identifier of the selected item or null if no item is selected. In multiple selection mode (see below), the value is a Set of item identifiers. Notice that the set is unmodifiable, so you can not simply change it to change the selection.

Multiple Selection Mode

A table can also be in multiselect mode, where a user can select multiple items by clicking them with left mouse button while holding the Ctrl key (or Meta key) pressed. If Ctrl is not held, clicking an item will select it and other selected items are deselected. The user can select a range by selecting an item, holding the Shift key pressed, and clicking another item, in which case all the items between the two are also selected. Multiple ranges can be selected by first selecting a range, then selecting an item while holding Ctrl, and then selecting another item with both Ctrl and Shift pressed.

The multiselect mode is enabled with the setMultiSelect() method of the AbstractSelect superclass of Table. Setting table in multiselect mode does not implicitly set it as selectable, so it must be set separately.

The setMultiSelectMode() property affects the control of multiple selection: MultiSelectMode.DEFAULT is the default behaviour, which requires holding the Ctrl (or Meta) key pressed while selecting items, while in MultiSelectMode.SIMPLE holding the Ctrl key is not needed. In the simple mode, items can only be deselected by clicking them.

5.21.2. Table Features

Page Length and Scrollbar

The default style for Table provides a table with a scrollbar. The scrollbar is located at the right side of the table and becomes visible when the number of items in the table exceeds the page length, that is, the number of visible items. You can set the page length with setPageLength().

Setting the page length to zero makes all the rows in a table visible, no matter how many rows there are. Notice that this also effectively disables buffering, as all the entire table is loaded to the browser at once. Using such tables to generate reports does not scale up very well, as there is some inevitable overhead in rendering a table with Ajax. For very large reports, generating HTML directly is a more scalable solution.

Resizing Columns

You can set the width of a column programmatically from the server-side with setColumnWidth(). The column is identified by the property ID and the width is given in pixels.

The user can resize table columns by dragging the resize handle between two columns. Resizing a table column causes a ColumnResizeEvent, which you can handle with a Table.ColumnResizeListener. The table must be set in immediate mode if you want to receive the resize events immediately, which is typical.

table.addColumnResizeListener(new Table.ColumnResizeListener(){
    public void columnResize(ColumnResizeEvent event) {
        // Get the new width of the resized column
        int width = event.getCurrentWidth();
        
        // Get the property ID of the resized column
        String column = (String) event.getPropertyId();

        // Do something with the information
        table.setColumnFooter(column, String.valueOf(width) + "px");
    }
});
        
// Must be immediate to send the resize events immediately
table.setImmediate(true);

See Figure 5.45, “Resizing Columns” for a result after the columns of a table has been resized.

Figure 5.45. Resizing Columns

Resizing Columns

Reordering Columns

If setColumnReorderingAllowed(true) is set, the user can reorder table columns by dragging them with the mouse from the column header,

Collapsing Columns

When setColumnCollapsingAllowed(true) is set, the right side of the table header shows a drop-down list that allows selecting which columns are shown. Collapsing columns is different than hiding columns with setVisibleColumns(), which hides the columns completely so that they can not be made visible (uncollapsed) from the user interface.

You can collapse columns programmatically with setColumnCollapsed(). Collapsing must be enabled before collapsing columns with the method or it will throw an IllegalAccessException.

// Allow the user to collapse and uncollapse columns
table.setColumnCollapsingAllowed(true);

// Collapse this column programmatically
try {
    table.setColumnCollapsed("born", true);
} catch (IllegalAccessException e) {
    // Can't occur - collapsing was allowed above
    System.err.println("Something horrible occurred");
}
        
// Give enough width for the table to accommodate the
// initially collapsed column later
table.setWidth("250px");

See Figure 5.46, “Collapsing Columns”.

Figure 5.46. Collapsing Columns

Collapsing Columns

If the table has undefined width, it minimizes its width to fit the width of the visible columns. If some columns are initially collapsed, the width of the table may not be enough to accomodate them later, which will result in an ugly horizontal scrollbar. You should consider giving the table enough width to accomodate columns uncollapsed by the user.

Components Inside a Table

The cells of a Table can contain any user interface components, not just strings. If the rows are higher than the row height defined in the default theme, you have to define the proper row height in a custom theme.

When handling events for components inside a Table, such as for the Button in the example below, you usually need to know the item the component belongs to. Components do not themselves know about the table or the specific item in which a component is contained. Therefore, the handling method must use some other means for finding out the Item ID of the item. There are a few possibilities. Usually the easiest way is to use the setData() method to attach an arbitrary object to a component. You can subclass the component and include the identity information there. You can also simply search the entire table for the item with the component, although that solution may not be so scalable.

The example below includes table rows with a Label in HTML content mode, a multiline TextField, a CheckBox, and a Button that shows as a link.

// Create a table and add a style to allow setting the row height in theme.
final Table table = new Table();
table.addStyleName("components-inside");

/* Define the names and data types of columns.
 * The "default value" parameter is meaningless here. */
table.addContainerProperty("Sum",            Label.class,     null);
table.addContainerProperty("Is Transferred", CheckBox.class,  null);
table.addContainerProperty("Comments",       TextField.class, null);
table.addContainerProperty("Details",        Button.class,    null);

/* Add a few items in the table. */
for (int i=0; i<100; i++) {
    // Create the fields for the current table row
    Label sumField = new Label(String.format(
                   "Sum is <b>$%04.2f</b><br/><i>(VAT incl.)</i>",
                   new Object[] {new Double(Math.random()*1000)}),
                               ContentMode.HTML);
    CheckBox transferredField = new CheckBox("is transferred");
    
    // Multiline text field. This required modifying the 
    // height of the table row.
    TextField commentsField = new TextField();
    commentsField.setRows(3);
    
    // The Table item identifier for the row.
    Integer itemId = new Integer(i);
    
    // Create a button and handle its click. A Button does not
    // know the item it is contained in, so we have to store the
    // item ID as user-defined data.
    Button detailsField = new Button("show details");
    detailsField.setData(itemId);
    detailsField.addClickListener(new Button.ClickListener() {
        public void buttonClick(ClickEvent event) {
            // Get the item identifier from the user-defined data.
            Integer iid = (Integer)event.getButton().getData();
            Notification.show("Link " +
                              iid.intValue() + " clicked.");
        } 
    });
    detailsField.addStyleName("link");
    
    // Create the table row.
    table.addItem(new Object[] {sumField, transferredField,
                                commentsField, detailsField},
                  itemId);
}

// Show just three rows because they are so high.
table.setPageLength(3);

The row height has to be set higher than the default with a style rule such as the following:

/* Table rows contain three-row TextField components. */
.v-table-components-inside .v-table-cell-content {
height: 54px;
}

The table will look as shown in Figure 5.47, “Components in a Table”.

Figure 5.47. Components in a Table

Components in a Table

Iterating Over a Table

As the items in a Table are not indexed, iterating over the items has to be done using an iterator. The getItemIds() method of the Container interface of Table returns a Collection of item identifiers over which you can iterate using an Iterator. For an example about iterating over a Table, please see Section 8.5, “Collecting Items in Containers”. Notice that you may not modify the Table during iteration, that is, add or remove items. Changing the data is allowed.

Filtering Table Contents

A table can be filtered if its container data source implements the Filterable interface, as the default IndexedContainer does. See Section 8.5.8, “Filterable Containers”.

5.21.3. Editing the Values in a Table

Normally, a Table simply displays the items and their fields as text. If you want to allow the user to edit the values, you can either put them inside components as we did earlier or simply call setEditable(true), in which case the cells are automatically turned into editable fields.

Let us begin with a regular table with a some columns with usual Java types, namely a Date, Boolean, and a String.

// Create a table. It is by default not editable.
final Table table = new Table();

// Define the names and data types of columns.
table.addContainerProperty("Date",     Date.class,  null);
table.addContainerProperty("Work",     Boolean.class, null);
table.addContainerProperty("Comments", String.class,  null);

// Add a few items in the table.
for (int i=0; i<100; i++) {
    Calendar calendar = new GregorianCalendar(2008,0,1);
    calendar.add(Calendar.DAY_OF_YEAR, i);
    
    // Create the table row.
    table.addItem(new Object[] {calendar.getTime(),
                                new Boolean(false),
                                ""},
                  new Integer(i)); // Item identifier
}

table.setPageLength(8);
layout.addComponent(table);

You could put the table in editable mode right away if you need to. We'll continue the example by adding a mechanism to switch the Table from and to the editable mode.

final CheckBox switchEditable = new CheckBox("Editable");
switchEditable.addValueChangeListener(
        new Property.ValueChangeListener() {
    public void valueChange(ValueChangeEvent event) {
        table.setEditable(((Boolean)event.getProperty()
                             .getValue()).booleanValue());
    }
});
switchEditable.setImmediate(true);
layout.addComponent(switchEditable);

Now, when you check to checkbox, the components in the table turn into editable fields, as shown in Figure 5.48, “A Table in Normal and Editable Mode”.

Figure 5.48. A Table in Normal and Editable Mode

A Table in Normal and Editable Mode

Field Factories

The field components that allow editing the values of particular types in a table are defined in a field factory that implements the TableFieldFactory interface. The default implementation is DefaultFieldFactory, which offers the following crude mappings:

Table 5.2. Type to Field Mappings in DefaultFieldFactory

Property TypeMapped to Field Class
DateA DateField.
BooleanA CheckBox.
ItemA Form (deprecated in Vaadin 7). The fields of the form are automatically created from the item's properties using a FormFieldFactory. The normal use for this property type is inside a Form and is less useful inside a Table.
otherA TextField. The text field manages conversions from the basic types, if possible.

Field factories are covered with more detail in Section 8.4, “Creating Forms by Binding Fields to Items”. You could just implement the TableFieldFactory interface, but we recommend that you extend the DefaultFieldFactory according to your needs. In the default implementation, the mappings are defined in the createFieldByPropertyType() method (you might want to look at the source code) both for tables and forms.

Navigation in Editable Mode

In the editable mode, the editor fields can have focus. Pressing Tab moves the focus to next column or, at the last column, to the first column of the next item. Respectively, pressing Shift+Tab moves the focus backward. If the focus is in the last column of the last visible item, the pressing Tab moves the focus outside the table. Moving backward from the first column of the first item moves the focus to the table itself. Some updates to the table, such as changing the headers or footers or regenerating a column, can move the focus from an editor component to the table itself.

The default behaviour may be undesirable in many cases. For example, the focus also goes through any read-only editor fields and can move out of the table inappropriately. You can provide better navigation is to use event handler for shortcut keys such as Tab, Arrow Up, Arrow Down, and Enter.

// Keyboard navigation
class KbdHandler implements Handler {
    Action tab_next = new ShortcutAction("Tab",
            ShortcutAction.KeyCode.TAB, null);
    Action tab_prev = new ShortcutAction("Shift+Tab",
            ShortcutAction.KeyCode.TAB,
            new int[] {ShortcutAction.ModifierKey.SHIFT});
    Action cur_down = new ShortcutAction("Down",
            ShortcutAction.KeyCode.ARROW_DOWN, null);
    Action cur_up   = new ShortcutAction("Up",
            ShortcutAction.KeyCode.ARROW_UP,   null);
    Action enter   = new ShortcutAction("Enter",
            ShortcutAction.KeyCode.ENTER,      null);
    public Action[] getActions(Object target, Object sender) {
        return new Action[] {tab_next, tab_prev, cur_down,
                             cur_up, enter};
    }

    public void handleAction(Action action, Object sender,
                             Object target) {
        if (target instanceof TextField) {
            // Move according to keypress
            int itemid = (Integer) ((TextField) target).getData();
            if (action == tab_next || action == cur_down)
                itemid++;
            else if (action == tab_prev || action == cur_up)
                itemid--;
            // On enter, just stay where you were. If we did
            // not catch the enter action, the focus would be
            // moved to wrong place.
            
            if (itemid >= 0 && itemid < table.size()) {
                TextField newTF = valueFields.get(itemid);
                if (newTF != null)
                    newTF.focus();
            }
        }
    }
}

// Panel that handles keyboard navigation
Panel navigator = new Panel();
navigator.addStyleName(Reindeer.PANEL_LIGHT);
navigator.addComponent(table);
navigator.addActionHandler(new KbdHandler());

The main issue in implementing keyboard navigation in an editable table is that the editor fields do not know the table they are in. To find the parent table, you can either look up in the component container hierarchy or simply store a reference to the table with setData() in the field component. The other issue is that you can not acquire a reference to an editor field from the Table component. One solution is to use some external collection, such as a HashMap, to map item IDs to the editor fields.

// Can't access the editable components from the table so
// must store the information
final HashMap<Integer,TextField> valueFields =
    new HashMap<Integer,TextField>();

The map has to be filled in a TableFieldFactory, such as in the following. You also need to set the reference to the table there and you can also set the initial focus there.

table.setTableFieldFactory(new TableFieldFactory () {
    public Field createField(Container container, Object itemId,
            Object propertyId, Component uiContext) {
        TextField field = new TextField((String) propertyId);
        
        // User can only edit the numeric column
        if ("Source of Fear".equals(propertyId))
            field.setReadOnly(true);
        else { // The numeric column
            // The field needs to know the item it is in
            field.setData(itemId);
            
            // Remember the field
            valueFields.put((Integer) itemId, field);
            
            // Focus the first editable value
            if (((Integer)itemId) == 0)
                field.focus();
        }
        return field;
    }
});

The issues are complicated by the fact that the editor fields are not generated for the entire table, but only for a cache window that includes the visible items and some items above and below it. For example, if the beginning of a big scrollable table is visible, the editor component for the last item does not exist. This issue is relevant mostly if you want to have wrap-around navigation that jumps from the last to first item and vice versa.

5.21.4. Column Headers and Footers

Table supports both column headers and footers; the headers are enabled by default.

Headers

The table header displays the column headers at the top of the table. You can use the column headers to reorder or resize the columns, as described earlier. By default, the header of a column is the property ID of the column, unless given explicitly with setColumnHeader().

// Define the properties
table.addContainerProperty("lastname", String.class, null);
table.addContainerProperty("born", Integer.class, null);
table.addContainerProperty("died", Integer.class, null);

// Set nicer header names
table.setColumnHeader("lastname", "Name");
table.setColumnHeader("born", "Born");
table.setColumnHeader("died", "Died");

The text of the column headers and the visibility of the header depends on the column header mode. The header is visible by default, but you can disable it with setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN).

Footers

The table footer can be useful for displaying sums or averages of values in a column, and so on. The footer is not visible by default; you can enable it with setFooterVisible(true). Unlike in the header, the column headers are empty by default. You can set their value with setColumnFooter(). The columns are identified by their property ID.

The following example shows how to calculate average of the values in a column:

// Have a table with a numeric column
Table table = new Table("Custom Table Footer");
table.addContainerProperty("Name", String.class, null);
table.addContainerProperty("Died At Age", Integer.class, null);
        
// Insert some data
Object people[][] = { {"Galileo",  77},
                      {"Monnier",  83},
                      {"Vaisala",  79},
                      {"Oterma",   86}};
for (int i=0; i<people.length; i++)
    table.addItem(people[i], new Integer(i));
        
// Calculate the average of the numeric column
double avgAge = 0;
for (int i=0; i<people.length; i++)
    avgAge += (Integer) people[i][1];
avgAge /= people.length;

// Set the footers
table.setFooterVisible(true);
table.setColumnFooter("Name", "Average");
table.setColumnFooter("Died At Age", String.valueOf(avgAge));

// Adjust the table height a bit
table.setPageLength(table.size());

The resulting table is shown in Figure 5.49, “A Table with a Footer”.

Figure 5.49. A Table with a Footer

A Table with a Footer

Handling Mouse Clicks on Headers and Footers

Normally, when the user clicks a column header, the table will be sorted by the column, assuming that the data source is Sortable and sorting is not disabled. In some cases, you might want some other functionality when the user clicks the column header, such as selecting the column in some way.

Clicks in the header cause a HeaderClickEvent, which you can handle with a Table.HeaderClickListener. Click events on the table header (and footer) are, like button clicks, sent immediately to server, so there is no need to set setImmediate().

// Handle the header clicks
table.addHeaderClickListener(new Table.HeaderClickListener() {
    public void headerClick(HeaderClickEvent event) {
        String column = (String) event.getPropertyId();
        Notification.show("Clicked " + column +
                "with " + event.getButtonName());
    }
});
        
// Disable the default sorting behavior
table.setSortDisabled(true);

Setting a click handler does not automatically disable the sorting behavior of the header; you need to disable it explicitly with setSortDisabled(true). Header click events are not sent when the user clicks the column resize handlers to drag them.

The HeaderClickEvent object provides the identity of the clicked column with getPropertyId(). The getButton() reports the mouse button with which the click was made: BUTTON_LEFT, BUTTON_RIGHT, or BUTTON_MIDDLE. The getButtonName() a human-readable button name in English: "left", "right", or "middle". The isShiftKey(), isCtrlKey(), etc., methods indicate if the Shift, Ctrl, Alt or other modifier keys were pressed during the click.

Clicks in the footer cause a FooterClickEvent, which you can handle with a Table.FooterClickListener. Footers do not have any default click behavior, like the sorting in the header. Otherwise, handling clicks in the footer is equivalent to handling clicks in the header.

5.21.5. Generated Table Columns

A table can have generated columns which values can be calculated based on the values in other columns. The columns are generated with a class implementing the Table.ColumnGenerator interface.

The GeneratedPropertyContainer described in Section 8.5.7, “GeneratedPropertyContainer is another way to accomplish the same task at container level. In addition to generating values, you can also use the feature for formatting or styling columns.

Defining a Column Generator

Column generators are objects that implement the Table.ColumnGenerator interface and its generateCell() method. The method gets the identity of the item and column as its parameters, in addition to the table object, and has to return a component. The interface is functional, so you can also define it by a lambda expression or a method reference in Java 8.

The following example defines a generator for formatting Double valued fields according to a format string (as in java.util.Formatter).

/** Formats the value in a column containing Double objects. */
class ValueColumnGenerator implements Table.ColumnGenerator {
    String format; /* Format string for the Double values. */

    /**
     * Creates double value column formatter with the given
     * format string.
     */
    public ValueColumnGenerator(String format) {
        this.format = format;
    }

    /**
     * Generates the cell containing the Double value.
     * The column is irrelevant in this use case.
     */
    public Component generateCell(Table source, Object itemId,
                                  Object columnId) {
        // Get the object stored in the cell as a property
        Property prop =
            source.getItem(itemId).getItemProperty(columnId);
        if (prop.getType().equals(Double.class)) {
            Label label = new Label(String.format(format,
                    new Object[] { (Double) prop.getValue() }));
            
            // Set styles for the column: one indicating that it's
            // a value and a more specific one with the column
            // name in it. This assumes that the column name
            // is proper for CSS.
            label.addStyleName("column-type-value");
            label.addStyleName("column-" + (String) columnId);
            return label;
        }
        return null;
    }
}

The column generator is called for all the visible (or more accurately cached) items in a table. If the user scrolls the table to another position in the table, the columns of the new visible rows are generated dynamically.

Generated column cells are automatically updated when a property value in the table row changes. Note that a generated cell, even if it is a field, does not normally have a property value bound to the table's container, so changes in generated columns do not trigger updates in other generated columns. It should also be noted that if a generated column cell depends on values in other rows, changes in the other rows do not trigger automatic update. You can get notified of such value changes by listening for them with a ValueChangeListener in the generated components. If you do so, you must remove such listeners when the generated components are detached from the UI or otherwise the listeners will accumulate in the container when the table is scrolled back and forth, causing possibly severe memory leak.

Adding Generated Columns

You add new generated columns to a Table with addGeneratedColumn(). It takes a property ID of the generated column as the first parameter and the generator as the second.

// Define the generated columns and their generators
table.addGeneratedColumn("date", // Java 8:
                         this::generateNonEditableCell);
table.addGeneratedColumn("price",
                         new PriceColumnGenerator());
table.addGeneratedColumn("consumption",
                         new ConsumptionColumnGenerator());
table.addGeneratedColumn("dailycost",
                         new DailyCostColumnGenerator());

Notice that the addGeneratedColumn() always places the generated columns as the last column, even if you defined some other order previously. You will have to set the proper order with setVisibleColumns().

table.setVisibleColumns("date", "quantity", "price", "total");

Generators in Editable Table

When you set a table as editable, table cells change to editable fields. When the user changes the values in the fields, the generated cells in the same row are updated automatically. However, putting a table with generated columns in editable mode has a few quirks. One is that the editable mode does not affect generated columns. You have two alternatives: either you generate the editing fields in the generator or, in case of formatter generators, remove the generators in the editable mode to allow editing the values. The following example uses the latter approach.

// Have a check box that allows the user
// to make the quantity and total columns editable.
final CheckBox editable = new CheckBox(
    "Edit the input values - calculated columns are regenerated");

editable.setImmediate(true);
editable.addClickListener(new ClickListener() {
    public void buttonClick(ClickEvent event) {
        table.setEditable(editable.booleanValue());
        
        // The columns may not be generated when we want to
        // have them editable.
        if (editable.booleanValue()) {
            table.removeGeneratedColumn("quantity");
            table.removeGeneratedColumn("total");
        } else { // Not editable
            // Show the formatted values.
            table.addGeneratedColumn("quantity",
                new ValueColumnGenerator("%.2f l"));
            table.addGeneratedColumn("total",
                new ValueColumnGenerator("%.2f e"));
        }
        // The visible columns are affected by removal
        // and addition of generated columns so we have
        // to redefine them.
        table.setVisibleColumns("date", "quantity",
                 "price", "total", "consumption", "dailycost");
    }
});

You will also have to set the editing fields in immediate mode to have the update occur immediately when an edit field loses the focus. You can set the fields in immediate mode with the a custom TableFieldFactory, such as the one given below, that just extends the default implementation to set the mode:

public class ImmediateFieldFactory extends DefaultFieldFactory {
    public Field createField(Container container,
                             Object itemId,
                             Object propertyId,
                             Component uiContext) {
        // Let the DefaultFieldFactory create the fields...
        Field field = super.createField(container, itemId,
                                        propertyId, uiContext);
        
        // ...and just set them as immediate.
        ((AbstractField)field).setImmediate(true);
        
        return field;
    }
}
...
table.setTableFieldFactory(new ImmediateFieldFactory());

If you generate the editing fields with the column generator, you avoid having to use such a field factory, but of course have to generate the fields for both normal and editable modes.

Figure 5.50, “Table with Generated Columns in Normal and Editable Mode” shows a table with columns calculated (blue) and simply formatted (black) with column generators.

Figure 5.50. Table with Generated Columns in Normal and Editable Mode

Table with Generated Columns in Normal and Editable Mode
Table with Generated Columns in Normal and Editable Mode

5.21.6. Formatting Table Columns

The displayed values of properties shown in a table are normally formatted using the toString() method of each property. Customizing the format in a table column can be done in several ways:

  • Using ColumnGenerator to generate a second column that is formatted. The original column needs to be set invisible. See Section 5.21.5, “Generated Table Columns”.
  • Using a Converter to convert between the property data model and its representation in the table.
  • Using a GeneratedPropertyContainer as a wrapper around the actual container to provide formatting.
  • Overriding the default formatPropertyValue() in Table.

As using a PropertyFormatter is generally much more awkward than overriding the formatPropertyValue(), its use is not described here.

You can override formatPropertyValue() as is done in the following example:

// Create a table that overrides the default
// property (column) format
final Table table = new Table("Formatted Table") {
    @Override
    protected String formatPropertyValue(Object rowId,
            Object colId, Property property) {
        // Format by property type
        if (property.getType() == Date.class) {
            SimpleDateFormat df =
                new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            return df.format((Date)property.getValue());
        }

        return super.formatPropertyValue(rowId, colId, property);
    }
};
        
// The table has some columns
table.addContainerProperty("Time", Date.class, null);
        
... Fill the table with data ...

You can also distinguish between columns by the colId parameter, which is the property ID of the column. DecimalFormat is useful for formatting decimal values.

... in formatPropertyValue() ...
} else if ("Value".equals(pid)) {
    // Format a decimal value for a specific locale
    DecimalFormat df = new DecimalFormat("#.00",
            new DecimalFormatSymbols(locale));
    return df.format((Double) property.getValue());
}
...
table.addContainerProperty("Value", Double.class, null);

A table with the formatted date and decimal value columns is shown in Figure 5.51, “Formatted Table Columns”.

Figure 5.51. Formatted Table Columns

Formatted Table Columns

You can use CSS for further styling of table rows, columns, and individual cells by using a CellStyleGenerator. It is described in Section 5.21.7, “CSS Style Rules”.

5.21.7. CSS Style Rules

Styling the overall style of a Table can be done with the following CSS rules.

.v-table {}
  .v-table-header-wrap {}
    .v-table-header {}
      .v-table-header-cell {}
        .v-table-resizer {} /* Column resizer handle. */
        .v-table-caption-container {}
  .v-table-body {}
    .v-table-row-spacer {}
    .v-table-table {}
      .v-table-row {}
        .v-table-cell-content {}

Notice that some of the widths and heights in a table are calculated dynamically and can not be set in CSS.

Setting Individual Cell Styles

The Table.CellStyleGenerator interface allows you to set the CSS style for each individual cell in a table. You need to implement the getStyle(), which gets the row (item) and column (property) identifiers as parameters and can return a style name for the cell. The returned style name will be concatenated to prefix "v-table-cell-content-".

The getStyle() is called also for each row, so that the propertyId parameter is null. This allows setting a row style.

Alternatively, you can use a Table.ColumnGenerator (see Section 5.21.5, “Generated Table Columns”) to generate the actual UI components of the cells and add style names to them.

Table table = new Table("Table with Cell Styles");
table.addStyleName("checkerboard");

// Add some columns in the table. In this example, the property
// IDs of the container are integers so we can determine the
// column number easily.
table.addContainerProperty("0", String.class, null, "", null, null);
for (int i=0; i<8; i++)
    table.addContainerProperty(""+(i+1), String.class, null,
                         String.valueOf((char) (65+i)), null, null);

// Add some items in the table.
table.addItem(new Object[]{
    "1", "R", "N", "B", "Q", "K", "B", "N", "R"}, new Integer(0));
table.addItem(new Object[]{
    "2", "P", "P", "P", "P", "P", "P", "P", "P"}, new Integer(1));
for (int i=2; i<6; i++)
    table.addItem(new Object[]{String.valueOf(i+1), 
                 "", "", "", "", "", "", "", ""}, new Integer(i));
table.addItem(new Object[]{
    "7", "P", "P", "P", "P", "P", "P", "P", "P"}, new Integer(6));
table.addItem(new Object[]{
    "8", "R", "N", "B", "Q", "K", "B", "N", "R"}, new Integer(7));
table.setPageLength(8);

// Set cell style generator
table.setCellStyleGenerator(new Table.CellStyleGenerator() {
    public String getStyle(Object itemId, Object propertyId) {
        // Row style setting, not relevant in this example.
        if (propertyId == null)
            return "green"; // Will not actually be visible

        int row = ((Integer)itemId).intValue();
        int col = Integer.parseInt((String)propertyId);
        
        // The first column.
        if (col == 0)
            return "rowheader";
        
        // Other cells.
        if ((row+col)%2 == 0)
            return "black";
        else
            return "white";
    }
});

You can then style the cells, for example, as follows:

/* Center the text in header. */
.v-table-header-cell {
    text-align: center;
}

/* Basic style for all cells. */
.v-table-checkerboard .v-table-cell-content {
    text-align: center;
    vertical-align: middle;
    padding-top: 12px;
    width: 20px;
    height: 28px;
}

/* Style specifically for the row header cells. */
.v-table-cell-content-rowheader {
	background: #E7EDF3
     url(../default/table/img/header-bg.png) repeat-x scroll 0 0;
}

/* Style specifically for the "white" cells. */
.v-table-cell-content-white {
    background: white;
    color: black;
}

/* Style specifically for the "black" cells. */
.v-table-cell-content-black {
    background: black;
    color: white;
}

The table will look as shown in Figure 5.52, “Cell Style Generator for a Table”.

Figure 5.52. Cell Style Generator for a Table

Cell Style Generator for a Table

Preface
1. Introduction
1.1. Overview
1.2. Example Application Walkthrough
1.3. Support for the Eclipse IDE
1.4. Goals and Philosophy
1.5. Background
2. Getting Started with Vaadin
2.1. Overview
2.2. Setting up the Development Environment
2.2.1. Installing Java SDK
2.2.2. Installing Eclipse IDE
2.2.3. Installing Apache Tomcat
2.2.4. Firefox and Firebug
2.3. Overview of Vaadin Libraries
2.4. Installing Vaadin Plugin for Eclipse
2.4.1. Installing the IvyDE Plugin
2.4.2. Installing the Vaadin Plugin
2.4.3. Updating the Plugins
2.4.4. Updating the Vaadin Libraries
2.5. Creating and Running a Project with Eclipse
2.5.1. Creating the Project
2.5.2. Exploring the Project
2.5.3. Coding Tips for Eclipse
2.5.4. Setting Up and Starting the Web Server
2.5.5. Running and Debugging
2.6. Using Vaadin with Maven
2.6.1. Working from Command-Line
2.6.2. Compiling and Running the Application
2.6.3. Using Add-ons and Custom Widget Sets
2.7. Creating a Project with NetBeans IDE
2.7.1. Maven Project from a Vaadin Archetype
2.8. Creating a Project with IntelliJ IDEA
2.8.1. Configuring an Application Server
2.8.2. Creating a Vaadin Web Application Project
2.8.3. Creating a Maven Project
2.9. Vaadin Installation Package
2.9.1. Package Contents
2.9.2. Installing the Libraries
2.10. Using Vaadin with Scala
3. Architecture
3.1. Overview
3.2. Technological Background
3.2.1. HTML and JavaScript
3.2.2. Styling with CSS and Sass
3.2.3. AJAX
3.2.4. Google Web Toolkit
3.2.5. Java Servlets
3.3. Client-Side Engine
3.4. Events and Listeners
4. Writing a Server-Side Web Application
4.1. Overview
4.2. Building the UI
4.2.1. Application Architecture
4.2.2. Compositing Components
4.2.3. View Navigation
4.2.4. Accessing UI, Page, Session, and Service
4.3. Designing UIs Declaratively
4.3.1. Declarative Syntax
4.3.2. Component Elements
4.3.3. Component Attributes
4.3.4. Component Identifiers
4.3.5. Using Designs in Code
4.4. Handling Events with Listeners
4.4.1. Using Anonymous Classes
4.4.2. Handling Events in Java 8
4.4.3. Implementing a Listener in a Regular Class
4.4.4. Differentiating Between Event Sources
4.5. Images and Other Resources
4.5.1. Resource Interfaces and Classes
4.5.2. File Resources
4.5.3. Class Loader Resources
4.5.4. Theme Resources
4.5.5. Stream Resources
4.6. Handling Errors
4.6.1. Error Indicator and Message
4.6.2. Customizing System Messages
4.6.3. Handling Uncaught Exceptions
4.7. Notifications
4.7.1. Notification Type
4.7.2. Customizing Notifications
4.7.3. Styling with CSS
4.8. Application Lifecycle
4.8.1. Deployment
4.8.2. Vaadin Servlet, Portlet, and Service
4.8.3. User Session
4.8.4. Loading a UI
4.8.5. UI Expiration
4.8.6. Closing UIs Explicitly
4.8.7. Session Expiration
4.8.8. Closing a Session
4.9. Deploying an Application
4.9.1. Creating Deployable WAR in Eclipse
4.9.2. Web Application Contents
4.9.3. Web Servlet Class
4.9.4. Using a web.xml Deployment Descriptor
4.9.5. Servlet Mapping with URL Patterns
4.9.6. Other Servlet Configuration Parameters
4.9.7. Deployment Configuration
5. User Interface Components
5.1. Overview
5.2. Interfaces and Abstractions
5.2.1. Component Interface
5.2.2. AbstractComponent
5.3. Common Component Features
5.3.1. Caption
5.3.2. Description and Tooltips
5.3.3. Enabled
5.3.4. Icon
5.3.5. Locale
5.3.6. Read-Only
5.3.7. Style Name
5.3.8. Visible
5.3.9. Sizing Components
5.3.10. Managing Input Focus
5.4. Field Components
5.4.1. Field Interface
5.4.2. Data Binding and Conversions
5.4.3. Handling Field Value Changes
5.4.4. Field Buffering
5.4.5. Field Validation
5.5. Selection Components
5.5.1. Binding Selection Components to Data
5.5.2. Adding New Items
5.5.3. Item Captions
5.5.4. Getting and Setting Selection
5.5.5. Handling Selection Changes
5.5.6. Allowing Adding New Items
5.5.7. Multiple Selection
5.5.8. Item Icons
5.6. Component Extensions
5.7. Label
5.7.1. Text Width and Wrapping
5.7.2. Content Mode
5.7.3. Spacing with a Label
5.7.4. Data Binding
5.7.5. CSS Style Rules
5.8. Link
5.9. TextField
5.9.1. Data Binding
5.9.2. String Length
5.9.3. Handling Null Values
5.9.4. Text Change Events
5.9.5. CSS Style Rules
5.10. TextArea
5.11. PasswordField
5.12. RichTextArea
5.13. Date and Time Input with DateField
5.13.1. PopupDateField
5.13.2. InlineDateField
5.13.3. Date and Time Resolution
5.13.4. DateField Locale
5.13.5. Week Numbers
5.14. Button
5.15. CheckBox
5.16. ComboBox
5.16.1. Filtered Selection
5.17. ListSelect
5.18. NativeSelect
5.19. OptionGroup
5.19.1. Disabling Items
5.20. TwinColSelect
5.21. Table
5.21.1. Selecting Items in a Table
5.21.2. Table Features
5.21.3. Editing the Values in a Table
5.21.4. Column Headers and Footers
5.21.5. Generated Table Columns
5.21.6. Formatting Table Columns
5.21.7. CSS Style Rules
5.22. Tree
5.23. TreeTable
5.23.1. Expanding and Collapsing Items
5.24. Grid
5.24.1. Overview
5.24.2. Binding to Data
5.24.3. Handling Selection Changes
5.24.4. Configuring Columns
5.24.5. Generating Columns
5.24.6. Column Renderers
5.24.7. Header and Footer
5.24.8. Filtering
5.24.9. Sorting
5.24.10. Editing
5.24.11. Programmatic Scrolling
5.24.12. Generating Row or Cell Styles
5.24.13. Styling with CSS
5.25. MenuBar
5.26. Upload
5.27. ProgressBar
5.28. Slider
5.29. PopupView
5.30. Calendar
5.30.1. Date Range and View Mode
5.30.2. Calendar Events
5.30.3. Getting Events from a Container
5.30.4. Implementing an Event Provider
5.30.5. Styling a Calendar
5.30.6. Visible Hours and Days
5.30.7. Drag and Drop
5.30.8. Using the Context Menu
5.30.9. Localization and Formatting
5.30.10. Customizing the Calendar
5.30.11. Backward and Forward Navigation
5.30.12. Date Click Handling
5.30.13. Handling Week Clicks
5.30.14. Handling Event Clicks
5.30.15. Event Dragging
5.30.16. Handling Drag Selection
5.30.17. Resizing Events
5.31. Composition with CustomComponent
5.32. Composite Fields with CustomField
5.33. Embedded Resources
5.33.1. Embedded Image
5.33.2. Adobe Flash Graphics
5.33.3. BrowserFrame
5.33.4. Generic Embedded Objects
6. Managing Layout
6.1. Overview
6.2. UI, Window, and Panel Content
6.3. VerticalLayout and HorizontalLayout
6.3.1. Properties or Attributes
6.3.2. Spacing in Ordered Layouts
6.3.3. Sizing Contained Components
6.4. GridLayout
6.4.1. Sizing Grid Cells
6.5. FormLayout
6.6. Panel
6.6.1. Scrolling the Panel Content
6.7. Sub-Windows
6.7.1. Opening and Closing Sub-Windows
6.7.2. Window Positioning
6.7.3. Scrolling Sub-Window Content
6.7.4. Modal Sub-Windows
6.8. HorizontalSplitPanel and VerticalSplitPanel
6.9. TabSheet
6.9.1. Adding Tabs
6.9.2. Tab Objects
6.9.3. Tab Change Events
6.9.4. Enabling and Handling Closing Tabs
6.10. Accordion
6.11. AbsoluteLayout
6.12. CssLayout
6.12.1. CSS Injection
6.12.2. Browser Compatibility
6.13. Layout Formatting
6.13.1. Layout Size
6.13.2. Expanding Components
6.13.3. Layout Cell Alignment
6.13.4. Layout Cell Spacing
6.13.5. Layout Margins
6.14. Custom Layouts
7. Themes
7.1. Overview
7.2. Introduction to Cascading Style Sheets
7.2.1. Applying CSS to HTML
7.2.2. Basic CSS Rules
7.2.3. Matching by Element Class
7.2.4. Matching by Descendant Relationship
7.2.5. Importance of Cascading
7.2.6. Style Class Hierarchy of a Vaadin UI
7.2.7. Notes on Compatibility
7.3. Syntactically Awesome Stylesheets (Sass)
7.3.1. Sass Overview
7.3.2. Sass Basics with Vaadin
7.4. Compiling Sass Themes
7.4.1. Compiling On the Fly
7.4.2. Compiling in Eclipse
7.4.3. Compiling with Maven
7.4.4. Compiling in Command-line
7.4.5. Compiling with Ant
7.5. Creating and Using Themes
7.5.1. Sass Themes
7.5.2. Plain Old CSS Themes
7.5.3. Styling Standard Components
7.5.4. Built-in Themes
7.5.5. Add-on Themes
7.6. Creating a Theme in Eclipse
7.7. Valo Theme
7.7.1. Basic Use
7.7.2. Common Settings
7.7.3. Valo Mixins and Functions
7.7.4. Valo Fonts
7.7.5. Component Styles
7.7.6. Theme Optimization
7.8. Font Icons
7.8.1. Loading Icon Fonts
7.8.2. Basic Use
7.8.3. Using Font icons in HTML
7.8.4. Using Font Icons in Other Text
7.8.5. Custom Font Icons
7.9. Custom Fonts
7.9.1. Loading Local Fonts
7.9.2. Loading Web Fonts
7.9.3. Using Custom Fonts
7.10. Responsive Themes
8. Binding Components to Data
8.1. Overview
8.2. Properties
8.2.1. Property Viewers and Editors
8.2.2. ObjectProperty Implementation
8.2.3. Converting Between Property Type and Representation
8.2.4. Implementing the Property Interface
8.3. Holding properties in Items
8.3.1. The PropertysetItem Implementation
8.3.2. Wrapping a Bean in a BeanItem
8.4. Creating Forms by Binding Fields to Items
8.4.1. Simple Binding
8.4.2. Using a FieldFactory to Build and Bind Fields
8.4.3. Binding Member Fields
8.4.4. Buffering Forms
8.4.5. Binding Fields to a Bean
8.4.6. Bean Validation
8.5. Collecting Items in Containers
8.5.1. Basic Use of Containers
8.5.2. Container Subinterfaces
8.5.3. IndexedContainer
8.5.4. BeanContainer
8.5.5. BeanItemContainer
8.5.6. Iterating Over a Container
8.5.7. GeneratedPropertyContainer
8.5.8. Filterable Containers
9. Vaadin SQLContainer
9.1. Architecture
9.2. Getting Started with SQLContainer
9.2.1. Creating a connection pool
9.2.2. Creating the TableQuery Query Delegate
9.2.3. Creating the Container
9.3. Filtering and Sorting
9.3.1. Filtering
9.3.2. Sorting
9.4. Editing
9.4.1. Adding items
9.4.2. Fetching generated row keys
9.4.3. Version column requirement
9.4.4. Auto-commit mode
9.4.5. Modified state
9.5. Caching, Paging and Refreshing
9.5.1. Container Size
9.5.2. Page Length and Cache Size
9.5.3. Refreshing the Container
9.5.4. Cache Flush Notification Mechanism
9.6. Referencing Another SQLContainer
9.7. Making Freeform Queries
9.8. Non-Implemented Methods
9.9. Known Issues and Limitations
10. Vaadin Designer
10.1. Overview
10.2. Installation
10.2.1. Installing Eclipse and Plug-Ins
10.2.2. License
10.2.3. Uninstalling
10.3. Getting Started
10.3.1. Creating a Design
10.3.2. Vaadin Designer GUI Overview
10.4. Designing
10.4.1. About Layouts
10.4.2. Starting from Blank
10.4.3. Using Templates
10.4.4. Adding Components
10.4.5. Previewing
10.5. Theming and Styling
10.5.1. Theme Based on Valo
10.5.2. Theme File
10.6. Wiring It Up
10.6.1. Declarative Code
10.6.2. Java Code
10.7. Limitations
11. Advanced Web Application Topics
11.1. Handling Browser Windows
11.1.1. Opening Popup Windows
11.1.2. Closing Popup Windows
11.2. Embedding UIs in Web Pages
11.2.1. Embedding Inside a div Element
11.2.2. Embedding Inside an iframe Element
11.2.3. Cross-Site Embedding with the Vaadin XS Add-on
11.3. Debug Mode and Window
11.3.1. Enabling the Debug Mode
11.3.2. Opening the Debug Window
11.3.3. Debug Message Log
11.3.4. General Information
11.3.5. Inspecting Component Hierarchy
11.3.6. Communication Log
11.3.7. Debug Modes
11.4. Request Handlers
11.5. Shortcut Keys
11.5.1. Shortcut Keys for Default Buttons
11.5.2. Field Focus Shortcuts
11.5.3. Generic Shortcut Actions
11.5.4. Supported Key Codes and Modifier Keys
11.6. Printing
11.6.1. Printing the Browser Window
11.6.2. Opening a Print Window
11.6.3. Printing PDF
11.7. Google App Engine Integration
11.8. Common Security Issues
11.8.1. Sanitizing User Input to Prevent Cross-Site Scripting
11.9. Navigating in an Application
11.9.1. Setting Up for Navigation
11.9.2. Implementing a View
11.9.3. Handling URI Fragment Path
11.10. Advanced Application Architectures
11.10.1. Layered Architectures
11.10.2. Model-View-Presenter Pattern
11.11. Managing URI Fragments
11.11.1. Setting the URI Fragment
11.11.2. Reading the URI Fragment
11.11.3. Listening for URI Fragment Changes
11.11.4. Supporting Web Crawling
11.12. Drag and Drop
11.12.1. Handling Drops
11.12.2. Dropping Items On a Tree
11.12.3. Dropping Items On a Table
11.12.4. Accepting Drops
11.12.5. Dragging Components
11.12.6. Dropping on a Component
11.12.7. Dragging Files from Outside the Browser
11.13. Logging
11.14. JavaScript Interaction
11.14.1. Calling JavaScript
11.14.2. Handling JavaScript Function Callbacks
11.15. Accessing Session-Global Data
11.15.1. Passing References Around
11.15.2. Overriding attach()
11.15.3. ThreadLocal Pattern
11.16. Server Push
11.16.1. Installing the Push Support
11.16.2. Enabling Push for a UI
11.16.3. Accessing UI from Another Thread
11.16.4. Broadcasting to Other Users
11.17. Vaadin CDI Add-on
11.17.1. CDI Overview
11.17.2. Installing Vaadin CDI Add-on
11.17.3. Preparing Application for CDI
11.17.4. Injecting a UI with @CDIUI
11.17.5. Scopes
11.17.6. Deploying CDI UIs and Servlets
11.17.7. View Navigation
11.17.8. CDI Events
11.18. Vaadin Spring Add-on
11.18.1. Spring Overview
11.18.2. Quick Start with Vaadin Spring Boot
11.18.3. Installing Vaadin Spring Add-on
11.18.4. Preparing Application for Spring
11.18.5. Injecting a UI with @SpringUI
11.18.6. Scopes
11.18.7. View Navigation
11.18.8. Access Control
11.18.9. Deploying Spring UIs and Servlets
12. Portal Integration
12.1. Overview
12.2. Creating a Generic Portlet in Eclipse
12.2.1. Creating a Project with Vaadin Plugin
12.3. Developing Vaadin Portlets for Liferay
12.3.1. Defining Liferay Profile for Maven
12.3.2. Creating a Portlet Project with Maven
12.3.3. Creating a Portlet Project in Liferay IDE
12.3.4. Removing the Bundled Installation
12.3.5. Installing Vaadin Resources
12.4. Portlet UI
12.5. Deploying to a Portal
12.5.1. Portlet Deployment Descriptor
12.5.2. Liferay Portlet Descriptor
12.5.3. Liferay Display Descriptor
12.5.4. Liferay Plugin Package Properties
12.5.5. Using a Single Widget Set
12.5.6. Building the WAR Package
12.5.7. Deploying the WAR Package
12.6. Vaadin IPC for Liferay
12.6.1. Installing the Add-on
12.6.2. Basic Communication
12.6.3. Considerations
12.6.4. Communication Through Session Attributes
12.6.5. Serializing and Encoding Data
12.6.6. Communicating with Non-Vaadin Portlets
13. Client-Side Vaadin Development
13.1. Overview
13.2. Installing the Client-Side Development Environment
13.3. Client-Side Module Descriptor
13.3.1. Specifying a Stylesheet
13.3.2. Limiting Compilation Targets
13.4. Compiling a Client-Side Module
13.4.1. Vaadin Compiler Overview
13.4.2. Compiling in Eclipse
13.4.3. Compiling with Ant
13.4.4. Compiling with Maven
13.5. Creating a Custom Widget
13.5.1. A Basic Widget
13.5.2. Using the Widget
13.6. Debugging Client-Side Code
13.6.1. Launching Development Mode
13.6.2. Launching SuperDevMode
13.6.3. Debugging Java Code in Chrome
14. Client-Side Applications
14.1. Overview
14.2. Client-Side Module Entry-Point
14.2.1. Module Descriptor
14.3. Compiling and Running a Client-Side Application
14.4. Loading a Client-Side Application
15. Client-Side Widgets
15.1. Overview
15.2. GWT Widgets
15.3. Vaadin Widgets
15.4. Grid
15.4.1. Renderers
16. Integrating with the Server-Side
16.1. Overview
16.2. Starting It Simple With Eclipse
16.2.1. Creating a Widget
16.2.2. Compiling the Widget Set
16.3. Creating a Server-Side Component
16.3.1. Basic Server-Side Component
16.4. Integrating the Two Sides with a Connector
16.4.1. A Basic Connector
16.4.2. Communication with the Server-Side
16.5. Shared State
16.5.1. Accessing Shared State on Server-Side
16.5.2. Handing Shared State in a Connector
16.5.3. Handling Property State Changes with @OnStateChange
16.5.4. Delegating State Properties to Widget
16.5.5. Referring to Components in Shared State
16.5.6. Sharing Resources
16.6. RPC Calls Between Client- and Server-Side
16.6.1. RPC Calls to the Server-Side
16.7. Component and UI Extensions
16.7.1. Server-Side Extension API
16.7.2. Extension Connectors
16.8. Styling a Widget
16.8.1. Determining the CSS Class
16.8.2. Default Stylesheet
16.9. Component Containers
16.10. Advanced Client-Side Topics
16.10.1. Client-Side Processing Phases
16.11. Creating Add-ons
16.11.1. Exporting Add-on in Eclipse
16.11.2. Building Add-on with Ant
16.12. Migrating from Vaadin 6
16.12.1. Quick (and Dirty) Migration
16.13. Integrating JavaScript Components and Extensions
16.13.1. Example JavaScript Library
16.13.2. A Server-Side API for a JavaScript Component
16.13.3. Defining a JavaScript Connector
16.13.4. RPC from JavaScript to Server-Side
17. Using Vaadin Add-ons
17.1. Overview
17.2. Downloading Add-ons from Vaadin Directory
17.2.1. Compiling Widget Sets with an Ant Script
17.3. Installing Add-ons in Eclipse with Ivy
17.4. Using Add-ons in a Maven Project
17.4.1. Adding a Dependency
17.4.2. Compiling the Project Widget Set
17.4.3. Enabling Widget Set Compilation
17.5. Installing Commercial Vaadin Add-on Licence
17.5.1. Obtaining License Keys
17.5.2. Installing License Key in License File
17.5.3. Passing License Key as System Property
17.6. Troubleshooting
18. Vaadin Charts
18.1. Overview
18.2. Installing Vaadin Charts
18.2.1. Maven Dependency
18.2.2. Ivy Dependency
18.2.3. Installing License Key
18.3. Basic Use
18.3.1. Basic Chart Configuration
18.3.2. Plot Options
18.3.3. Chart Data Series
18.3.4. Axis Configuration
18.3.5. Displaying Multiple Series
18.3.6. Mixed Type Charts
18.3.7. 3D Charts
18.3.8. Chart Themes
18.4. Chart Types
18.4.1. Line and Spline Charts
18.4.2. Area Charts
18.4.3. Column and Bar Charts
18.4.4. Error Bars
18.4.5. Box Plot Charts
18.4.6. Scatter Charts
18.4.7. Bubble Charts
18.4.8. Pie Charts
18.4.9. Gauges
18.4.10. Solid Gauges
18.4.11. Area and Column Range Charts
18.4.12. Polar, Wind Rose, and Spiderweb Charts
18.4.13. Funnel and Pyramid Charts
18.4.14. Waterfall Charts
18.4.15. Heat Maps
18.4.16. Tree Maps
18.4.17. Polygons
18.5. Chart Configuration
18.5.1. Plot Options
18.5.2. Axes
18.5.3. Legend
18.5.4. Formatting Labels
18.6. Chart Data
18.6.1. List Series
18.6.2. Generic Data Series
18.6.3. Range Series
18.6.4. Container Data Series
18.6.5. Drill-Down
18.7. Advanced Uses
18.7.1. Server-Side Rendering and Exporting
18.8. Timeline
18.8.1. Graph types
18.8.2. Interaction Elements
18.8.3. Event Markers
18.8.4. Efficiency
18.8.5. Data Source Requirements
18.8.6. Events and Listeners
18.8.7. Configurability
18.8.8. Localization
18.8.9. Timeline Tutorial
19. Vaadin JPAContainer
19.1. Overview
19.2. Installing
19.2.1. Downloading the Package
19.2.2. Installation Package Content
19.2.3. Downloading with Maven
19.2.4. Including Libraries in Your Project
19.2.5. Persistence Configuration
19.2.6. Troubleshooting
19.3. Defining a Domain Model
19.3.1. Persistence Metadata
19.4. Basic Use of JPAContainer
19.4.1. Creating JPAContainer with JPAContainerFactory
19.4.2. Creating and Accessing Entities
19.4.3. Nested Properties
19.4.4. Hierarchical Container
19.5. Entity Providers
19.5.1. Built-In Entity Providers
19.5.2. Using JNDI Entity Providers in JEE6 Environment
19.5.3. Entity Providers as Enterprise Beans
19.6. Filtering JPAContainer
19.7. Querying with the Criteria API
19.7.1. Filtering the Query
19.7.2. Compatibility
19.8. Automatic Form Generation
19.8.1. Configuring the Field Factory
19.8.2. Using the Field Factory
19.8.3. Master-Detail Editor
19.9. Using JPAContainer with Hibernate
19.9.1. Lazy loading
19.9.2. The EntityManager-Per-Request pattern
19.9.3. Joins in Hibernate vs EclipseLink
20. Mobile Applications with TouchKit
20.1. Overview
20.2. Considerations Regarding Mobile Browsing
20.2.1. Mobile Human Interface
20.2.2. Bandwidth and Performance
20.2.3. Mobile Features
20.2.4. Compatibility
20.3. Installing Vaadin TouchKit
20.3.1. Installing as Ivy Dependency
20.3.2. Defining the Maven Dependency
20.3.3. Installing the Zip Package
20.4. Importing the Parking Demo
20.5. Creating a New TouchKit Project
20.5.1. Using the Maven Archetype
20.5.2. Starting from a New Eclipse Project
20.6. Elements of a TouchKit Application
20.6.1. The Servlet Class
20.6.2. Defining Servlet and UI with web.xml Deployment Descriptor
20.6.3. TouchKit Settings
20.6.4. The UI
20.6.5. Mobile Widget Set
20.6.6. Mobile Theme
20.6.7. Using Font Icons
20.7. Mobile User Interface Components
20.7.1. NavigationView
20.7.2. Toolbar
20.7.3. NavigationManager
20.7.4. NavigationButton
20.7.5. Popover
20.7.6. SwipeView
20.7.7. Switch
20.7.8. VerticalComponentGroup
20.7.9. HorizontalButtonGroup
20.7.10. TabBarView
20.7.11. EmailField
20.7.12. NumberField
20.7.13. UrlField
20.8. Advanced Mobile Features
20.8.1. Providing a Fallback UI
20.8.2. Geolocation
20.8.3. Storing Data in the Local Storage
20.8.4. Uploading Content
20.9. Offline Mode
20.9.1. Enabling the Cache Manifest
20.9.2. Enabling Offline Mode
20.9.3. The Offline User Interface
20.9.4. Sending Data to Server
20.9.5. The Offline Theme
20.10. Building an Optimized Widget Set
20.10.1. Generating the Widget Map
20.10.2. Defining the Widget Loading Style
20.10.3. Applying the Custom Widget Map Generator
20.10.4. Deployment
20.11. Testing and Debugging on Mobile Devices
20.11.1. Debugging
21. Vaadin Spreadsheet
21.1. Overview
21.2. Installing Vaadin Spreadsheet
21.2.1. Installing as Ivy Dependency
21.2.2. Defining the Maven Dependency
21.2.3. Installing the Zip Package
21.2.4. Installing License Key
21.2.5. Compiling Widget Set
21.2.6. Compiling Theme
21.2.7. Importing the Demo
21.3. Basic Use
21.3.1. Creating a Spreadsheet
21.3.2. Working with Sheets
21.4. Spreadsheet Configuration
21.4.1. Spreadsheet Elements
21.4.2. Frozen Row and Column Panes
21.5. Cell Content and Formatting
21.5.1. Cell Formatting
21.5.2. Cell Font Style
21.5.3. Cell Comments
21.5.4. Merging Cells
21.5.5. Components in Cells
21.5.6. Hyperlinks
21.5.7. Popup Buttons in Cells
21.6. Context Menus
21.6.1. Default Context Menu
21.6.2. Custom Context Menus
21.7. Tables Within Spreadsheets
21.7.1. Creating a Table
21.7.2. Filtering With a Table
22. Vaadin TestBench
22.1. Overview
22.2. Quick Start
22.2.1. Installing License Key
22.2.2. Quick Start with Eclipse
22.2.3. Quick Start with Maven
22.3. Installing Vaadin TestBench
22.3.1. Test Development Setup
22.3.2. A Distributed Testing Environment
22.3.3. Installation Package Contents
22.3.4. TestBench Demo
22.3.5. Installing Browser Drivers
22.3.6. Test Node Configuration
22.4. Developing JUnit Tests
22.4.1. Basic Test Case Structure
22.4.2. Running JUnit Tests in Eclipse
22.5. Creating a Test Case
22.5.1. Test Setup
22.5.2. Basic Test Case Structure
22.5.3. Creating and Closing a Web Driver
22.6. Querying Elements
22.6.1. Generating Queries with Debug Window
22.6.2. Querying Elements by Component Type ($)
22.6.3. Non-Recursive Component Queries ($$)
22.6.4. Element Classes
22.6.5. ElementQuery Objects
22.6.6. Query Terminators
22.7. Element Selectors
22.7.1. Finding by ID
22.7.2. Finding by CSS Class
22.8. Special Testing Topics
22.8.1. Waiting for Vaadin
22.8.2. Testing Tooltips
22.8.3. Scrolling
22.8.4. Testing Notifications
22.8.5. Testing Context Menus
22.8.6. Profiling Test Execution Time
22.9. Creating Maintainable Tests
22.9.1. Increasing Selector Robustness
22.9.2. The Page Object Pattern
22.10. Taking and Comparing Screenshots
22.10.1. Screenshot Parameters
22.10.2. Taking Screenshots on Failure
22.10.3. Taking Screenshots for Comparison
22.10.4. Practices for Handling Screenshots
22.10.5. Known Compatibility Problems
22.11. Running Tests
22.11.1. Running Tests with Ant
22.11.2. Running Tests with Maven
22.12. Running Tests in a Distributed Environment
22.12.1. Running Tests Remotely
22.12.2. Starting the Hub
22.12.3. Node Service Configuration
22.12.4. Starting a Grid Node
22.12.5. Mobile Testing
22.13. Parallel Execution of Tests
22.13.1. Local Parallel Execution
22.13.2. Multi-Browser Execution in a Grid
22.14. Headless Testing
22.14.1. Basic Setup for Running Headless Tests
22.14.2. Running Headless Tests in a Distributed Environment
22.15. Behaviour-Driven Development
22.16. Integration Testing with Maven
22.16.1. Project Structure
22.16.2. Overview of Lifecycle
22.16.3. Overview of Configuration
22.16.4. Vaadin Plugin Configuration
22.16.5. Configuring Integration Testing
22.16.6. Configuring Test Server
22.17. Known Issues
22.17.1. Running Firefox Tests on Mac OS X
Index
Need some help?

Training

Upcoming trainings

The official Vaadin trainings are the best way to learn the framework and tools. We offer the following courses.

Vaadin FundamentalsRead more »
Advanced VaadinRead more »
Extending VaadinRead more »
Vaadin & JavaEERead more »

Support

Learn more

For most of us, time is money and a support channel pays itself back in saved development time, developers' nerves and a faster time to market.