Grid: How to use a binder?

Hi everyone,

I have a simple example containing a customer who might have several addresses. This is my JPA model:

@Entity
@NamedEntityGraph(name = "addressGraph", attributeNodes = { @NamedAttributeNode("addresses") })
public class Customer {

	@Id
	@GeneratedValue
	private Long id;

	@Size(min = 3)
	private String firstName;

	private String lastName;

	@ElementCollection
	private List<@NotNull @Valid Address> addresses = new ArrayList<>();
@Embeddable
public class Address {

	@Size( min = 3)
	private String street;

	private String city;

I use a editable grid to maintain the addresses of a customer. I would like to use the binder as I would like to reflect the changes on the UI to the model. This is my appoach:

		addressGrid.addComponentColumn((address) -> {
			final Binder<Address> addressBinder = new BeanValidationBinder<>(Address.class);
			TextField street = new TextField();
			addressBinder.bind(street, Address::getStreet, Address::setStreet);
			addressBinder.setBean(address);
			return street;
		}).setHeader("Street");
		addressGrid.addComponentColumn((address) -> {
			final Binder<Address> addressBinder = new BeanValidationBinder<>(Address.class);
			TextField city = new TextField();
			addressBinder.bind(city, Address::getCity, Address::setCity);
			addressBinder.setBean(address);
			return city;
		}).setHeader("City");

It seems to work, but I wonder if it’s menaingful to create a binder for each column. Isn’t it sufficient to have a binder for each row? But how can I achieve this?

Thanks for your support.

Kind regards
Oliver

I think you would need a binder per row, because each row represents a bean and you have multiple rows(beans) not just one.

Grid row editing is not available on Vaadin 10.

I have the same question. Can anybody provide some solution how to use a binder per row?

In Vaadin 13, Grid row editing is possible. Please see the example [here]
(https://vaadin.com/components/vaadin-grid/java-examples/grid-editor).

Using OP’s models, an editable grid for a customers addresses could look like this:

// initialize grid
Grid<Address> grid = new Grid<>(Address.class);
grid.setColumns("street", "city");
grid.setItems(customer.getAddresses());

// prepare editor
Binder<Address> editorBinder = new Binder<>();
Editor<Address> editor = grid.getEditor();
editor.setBinder(editorBinder);
editor.setBuffered(true); // true --> the edited values will only be applied upon clicking save, instead of immediately at value change of editor textfield

// set an editor component for each column that is editable
TextField streetEditField = new TextField();
editorBinder.forField(streetEditField).bind(Address::getStreet, Address::setStreet);
grid.getColumnByKey("street").setEditorComponent(streetEditField);

TextField cityEditField = new TextField();
editorBinder.forField(cityEditField).bind(Address::getCity, Address::setCity);
grid.getColumnByKey("city").setEditorComponent(cityEditField);

// add a column for editor actions (edit, save, cancel)
Grid.Column<Address> editorColumn = grid.addColumn(new ComponentRenderer<>(item -> {
    Button editBtn = new Button("Edit", VaadinIcon.EDIT.create());
    editBtn.addClickListener(click -> {
        editor.editItem(item);
    });
    return editBtn;
}))
        .setKey("edit");

// show save and cancel buttons when in edit mode
Button save = new Button(VaadinIcon.CHECK_CIRCLE.create(), e -> editor.save());
Button cancel = new Button(VaadinIcon.CLOSE_CIRCLE.create(), e -> editor.cancel());
Div buttons = new Div(save, cancel);
editorColumn.setEditorComponent(buttons);

// Add a keypress listener that listens for an escape key up event.
// Note! some browsers return key as Escape and some as Esc
grid.getElement().addEventListener("keyup", event -> editor.cancel())
        .setFilter("event.key === 'Escape' || event.key === 'Esc'");
		
// saving the edits will lead to the address objects of the customer to change values without needing to add a saveListener.
// If you want to save either the customer or the address to the DB at this point, you can add a saveListener to the editor
editor.addSaveListener(saveEvent -> {
    // customerService.save(customer);
    // addressService.save(saveEvent.getItem());
});