Make only certain rows of the Vaadin 8 Grid editable

Hello

I am trying to use a Vaadin 8 Grid which has some rows (based on a property of the row item) which are not editable.
I have tried to do this with the addItemClickListener(…) but once the Grid editor is open the user can edit any row, also the once which are not supposed to be changed.

table.addItemClickListener(event -> {
	if (event.getItem().isReadOnly()) {
		editor.setEnabled(false);
	} else {
		editor.setEnabled(true);
	}
});

In the following thread was a proposed solution for the Vaadin 7 Grid but the Vaadin 8 Grid does not have the method addEditorCloseListener(…).

https://vaadin.com/forum/thread/10747751/make-some-rows-of-a-grid-non-editable

Is there any way to achieve this with a Vaadin 8 Grid?

Thanks in advance.
Best regards,
Bernhard

If you already use the grid editor, you can define editorBindings only on the columns that you want to be editable. Now when the editor is opened, only the specified columns have an Input field. All other columns are therefore not editable.

If you have a Person-grid with the columns firstName and lastName, this code will only allow edits to the firstName:

// prepare grid
Grid<Person> grid = new Grid<>();
Grid.Column<Person, ?> firstNameColumn = grid.addColumn(Person::getFirstName);
Grid.Column<Person, ?> lastNameColumn = grid.addColumn(Person::getLastName);

// prepare grid editor
grid.getEditor().setEnabled(true);
Binder<Person> editorBinder = grid.getEditor().getBinder();

// define edit components for all editable columns, in this case only firstNameColumn
TextField firstNameEditorField = new TextField();
Binder.Binding<Person, String> firstNameBinding = editorBinder.forField(firstNameEditorField).bind(Person::getFirstName, Person::setFirstName);
firstNameColumn.setEditorBinding(firstNameBinding);

and the used Person object

public class Person {
	private String firstName, lastName;
	public Person(String firstName, String lastName){
		this.firstName = firstName;
		this.lastName = lastName;
	}
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
}

Hello Kaspar, thank you for your answer. I got this with the binding on the columns, thank you for your good example.

In my case I have a column which is in generally editable so I have set the binding on that column, but I have certain rows which I don’t want the user to change. The binding makes all the fields editable of the column.
My question now is how can I make certain rows or fields of the Grid read only when the column contains editable fields?

By generally editable, do you mean there is currently an editable TextField in the cell even if the editor is not opened?

If so, then you did that probably similar to this: (using the abovedefined Person object again…)

grid.addComponentColumn(item -> {
	TextField lastNameField = new TextField();
	lastNameField.setValue(item.getLastname());
	lastNameField.addValueChangeListener(event -> {
	    item.setLastName(event.getValue());
	});
	return lastNameField;
});

You can change that to this, which will no longer allow direct editing of the value. It will only display the value, there is no input field.

grid.addColumn(Person::getFirstName);

There’s a chance that I misunderstood you. Maybe you want all columns to have their own TextField when in editor mode, but some textfields should be read-only. You can achieve a read-only state by passing null as the setter of the binding:

// prepare grid
Grid<Person> grid = new Grid<>();
Grid.Column<Person, ?> firstNameColumn = grid.addColumn(Person::getFirstName);
Grid.Column<Person, ?> lastNameColumn = grid.addColumn(Person::getLastName);

// prepare grid editor
grid.getEditor().setEnabled(true);
Binder<Person> editorBinder = grid.getEditor().getBinder();

// define edit components for all columns. 
// firstName -> editable
TextField firstNameEditorField = new TextField();
Binder.Binding<Person, String> firstNameBinding = editorBinder.forField(firstNameEditorField).bind(Person::getFirstName, Person::setFirstName);
firstNameColumn.setEditorBinding(firstNameBinding);

// lastName -> read-only! 
TextField lastNameEditorField = new TextField();
Binder.Binding<Person, String> lastNameBinding = editorBinder.forField(lastNameEditorField).bind(Person::getLastName, null); // null here will make the textfield read-only
lastNameColumn.setEditorBinding(lastNameBinding);

Hello Kaspar

Thank you for your help. I got it now.
I can do it using the addComponentColumn(…), this is exactely what I need.
Thank you for your code snippets, this helped me a lot.

oops I forgot to return the textField in that component column renderer, I edited that now. You probably noticed what was wrong yourself, if you say it worked for you :slight_smile:

always happy to help, Schöns Tägli :slight_smile:

Yes I noticed that, it works for me now. I almost gave up on this, thanks again for the help.

One solution is to use [Grid FastNavigation add-on]
(https://vaadin.com/directory/component/gridfastnavigation-add-on), it has some API for allowing conditional editing dynamically → https://vaadin.com/directory/component/gridfastnavigation-add-on/api/org/vaadin/patrik/events/EditorOpenEvent.html