Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Editing right in the grid: Grid Editor

Fixing a typo in a title should not require opening a separate form. The Grid Editor turns the cells of the chosen row into input fields: the user changes the text right in the grid, and the changes go to the database. The familiar Binder connects the fields to the post.

The editor has two modes. In buffered mode, changes wait for a "Save" button; in unbuffered mode, each field change is written to the object at once. The second mode is simpler and is the default, so we use it.

Fields for the editor

Add class fields to PostListView from the previous lessons:

// src/main/java/com/example/blog/views/PostListView.java (new fields)
private final Binder<Post> binder = new Binder<>(Post.class);
private final TextField titleField = new TextField();
private final TextField authorField = new TextField();

These are ordinary input fields, just without labels: a cell does not need one. Import: com.vaadin.flow.data.binder.Binder.

Setting up the editor

Keep the title and author columns in variables and attach the fields to them:

// src/main/java/com/example/blog/views/PostListView.java (part of the constructor)
Grid.Column<Post> titleColumn = grid.addColumn(Post::getTitle).setHeader("Title").setSortProperty("title");
Grid.Column<Post> authorColumn = grid.addColumn(Post::getAuthor).setHeader("Author").setSortProperty("author");
 
Editor<Post> editor = grid.getEditor();
editor.setBinder(binder);
binder.forField(titleField).asRequired("Enter a title").bind(Post::getTitle, Post::setTitle);
binder.forField(authorField).asRequired("Enter the author").bind(Post::getAuthor, Post::setAuthor);
titleField.setWidthFull();
authorField.setWidthFull();
titleColumn.setEditorComponent(titleField);
authorColumn.setEditorComponent(authorField);
 
editor.addCloseListener(event -> {
    service.save(event.getItem());
    Notification.show("Saved: " + event.getItem().getTitle());
});
grid.getElement().addEventListener("keydown", event -> editor.closeEditor())
        .setFilter("event.key === 'Enter' || event.key === 'Escape'");

setEditorComponent says which field to show in the column's cell while editing. Columns without one (date, status) stay plain text. The close listener saves the post to the database. The last two lines close the editor on Enter or Esc: setFilter is a JavaScript condition checked in the browser, so only these two keys reach the server. Import: com.vaadin.flow.component.grid.editor.Editor.

The Edit button

Let us open the editor with a pencil button in the actions column:

// src/main/java/com/example/blog/views/PostListView.java (actions method)
private HorizontalLayout actions(Post post) {
    Button edit = new Button(VaadinIcon.EDIT.create(), event -> {
        grid.getEditor().editItem(post);
        titleField.focus();
    });
    edit.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
    Button preview = new Button(VaadinIcon.EYE.create(), event -> preview(post));
    Button delete = new Button(VaadinIcon.TRASH.create(), event -> confirmDelete(post));
    preview.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
    delete.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_ERROR);
    return new HorizontalLayout(edit, preview, delete);
}

Click the pencil next to "Hello, Vaadin": the title and author in that row become fields, with the cursor in the title. Type " 25" and press Enter: the row turns back into text, "Hello, Vaadin 25", and "Saved: Hello, Vaadin 25" appears at the bottom. Reload the page and the new title is still there, because it was written to the database.

Validation in a cell

Delete the whole title and press Tab: the field turns red with "Enter a title" under it. In unbuffered mode, the Binder does not write an invalid value to the post, so after Esc the row and the database keep the previous title.

Editor methodWhat it does
setBinder(binder)Connects the editor fields to the row
editItem(item)Opens the editor for a row
closeEditor()Closes the editor (unbuffered mode)
setBuffered(true)Buffered mode: save() and cancel()
addCloseListener(...)Runs when the editor closes
isOpen()Whether the editor is open

Common mistake

Buffered mode was switched on, but the keys still call closeEditor():

// src/main/java/com/example/blog/views/PostListView.java (wrong)
editor.setBuffered(true);
grid.getElement().addEventListener("keydown", event -> editor.closeEditor())
        .setFilter("event.key === 'Enter' || event.key === 'Escape'");

Pressing Enter in the open editor ends with an exception:

java.lang.UnsupportedOperationException: Buffered editor should be closed using save() or cancel()

A buffered editor is closed only with editor.save() (write the changes) or editor.cancel() (discard them), and saving to the database goes into addSaveListener. If you do not need Save and Cancel buttons in the row, stay in unbuffered mode.

Thanks for reading!

Donate to the site — we work hard for you.