Правка прямо в таблице: Grid Editor
Чтобы поправить опечатку в заголовке, не хочется открывать отдельную форму. Редактор таблицы (Grid Editor) превращает ячейки выбранной строки в поля ввода: пользователь меняет текст прямо в таблице, а изменения уходят в базу. Связь полей со статьёй берёт на себя уже знакомый Binder.
У редактора два режима. В буферизованном (buffered) правки копятся до кнопки «Сохранить», в небуферизованном (unbuffered) каждое изменение поля сразу пишется в объект. Второй режим проще — он включён по умолчанию, его и возьмём.
Поля для редактора
В PostListView из прошлых уроков добавьте поля класса:
// src/main/java/com/example/blog/views/PostListView.java (новые поля)
private final Binder<Post> binder = new Binder<>(Post.class);
private final TextField titleField = new TextField();
private final TextField authorField = new TextField();Это обычные поля ввода, только без подписей: в ячейке подпись не нужна. Импорт — com.vaadin.flow.data.binder.Binder.
Настройка редактора
Колонки заголовка и автора сохраните в переменные и подключите к ним поля:
// src/main/java/com/example/blog/views/PostListView.java (фрагмент конструктора)
Grid.Column<Post> titleColumn = grid.addColumn(Post::getTitle).setHeader("Заголовок").setSortProperty("title");
Grid.Column<Post> authorColumn = grid.addColumn(Post::getAuthor).setHeader("Автор").setSortProperty("author");
Editor<Post> editor = grid.getEditor();
editor.setBinder(binder);
binder.forField(titleField).asRequired("Введите заголовок").bind(Post::getTitle, Post::setTitle);
binder.forField(authorField).asRequired("Укажите автора").bind(Post::getAuthor, Post::setAuthor);
titleField.setWidthFull();
authorField.setWidthFull();
titleColumn.setEditorComponent(titleField);
authorColumn.setEditorComponent(authorField);
editor.addCloseListener(event -> {
service.save(event.getItem());
Notification.show("Сохранено: " + event.getItem().getTitle());
});
grid.getElement().addEventListener("keydown", event -> editor.closeEditor())
.setFilter("event.key === 'Enter' || event.key === 'Escape'");setEditorComponent говорит, какое поле показать в ячейке колонки на время правки. Колонки без него (дата, статус) остаются обычным текстом. Обработчик закрытия сохраняет статью в базу. Последние две строки закрывают редактор по Enter или Esc: setFilter — условие на JavaScript, которое проверяется в браузере, поэтому на сервер приходят только эти две клавиши. Импорт — com.vaadin.flow.component.grid.editor.Editor.
Кнопка «Править»
Откроем редактор кнопкой-карандашом в колонке действий:
// src/main/java/com/example/blog/views/PostListView.java (метод actions)
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);
}Нажмите карандаш у «Привет, Vaadin»: заголовок и автор в этой строке станут полями, курсор встанет в заголовок. Допишите « 25» и нажмите Enter — строка снова станет текстом «Привет, Vaadin 25», а внизу появится «Сохранено: Привет, Vaadin 25». Обновите страницу — новый заголовок на месте, он записан в базу.
Проверка в ячейке
Сотрите заголовок целиком и нажмите Tab: поле подсветится красным с текстом «Введите заголовок» под ним. В небуферизованном режиме Binder не пишет в статью неверное значение, поэтому после Esc в строке и в базе останется прежний заголовок.
Метод Editor | Что делает |
|---|---|
setBinder(binder) | Связывает поля редактора со строкой |
editItem(item) | Открывает редактор для строки |
closeEditor() | Закрывает редактор (небуферизованный режим) |
setBuffered(true) | Буферизованный режим: save() и cancel() |
addCloseListener(...) | Срабатывает при закрытии |
isOpen() | Открыт ли редактор |
Частая ошибка
Включили буферизованный режим, а клавиши по-прежнему вызывают closeEditor():
// src/main/java/com/example/blog/views/PostListView.java (неправильно)
editor.setBuffered(true);
grid.getElement().addEventListener("keydown", event -> editor.closeEditor())
.setFilter("event.key === 'Enter' || event.key === 'Escape'");Нажатие Enter в открытом редакторе заканчивается исключением:
java.lang.UnsupportedOperationException: Buffered editor should be closed using save() or cancel()Буферизованный редактор закрывают только через editor.save() (записать правки) или editor.cancel() (отменить), а сохранение в базу делают в addSaveListener. Если кнопки «Сохранить» и «Отмена» в строке не нужны, оставайтесь в небуферизованном режиме.