Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Правка прямо в таблице: 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. Если кнопки «Сохранить» и «Отмена» в строке не нужны, оставайтесь в небуферизованном режиме.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.