Is it possible to set edit a long value in an editable Vaadin 8 Grid as wel

I have a Vaadin 8 Grid where I would like to set one column as editable.

For example I have a table of Food with one column called Food.calories which is a long (yes in this case it could be an int but my specific use case requires a long)

foodGrid.addColumn(Food::getCalories, new NumberRenderer(myNumberFormat))
        .setEditorComponent(new TextField(), Food::setCalories);

Unfortunately this doesn’t work and gives me the following error:

Inferred type ‘C’ for type parameter ‘C’ is not within its bound; should implement ‘com.vaadin.data.HasValue’

I tried to look for sample code,
including in the Demo
, but I couldn’t find any examples other than simple edits. Nothing with converters or validators:

So the first question is how do you resolve this error, in other words how can I edit a number? My second question is how can I add a validation. For example I want to make sure that the number of calories is a positive number.

You can set validation and conversion you want by getting the Binder of the editor with foodGrid.getEditor().getBinder().

With binder.forField(…).withValidator(…).withConverter(…) methods you can do what you are trying accomplish.

See more info here

https://vaadin.com/docs/-/part/framework/datamodel/datamodel-forms.html

I tried that but it still failed. For example the validator had a compiler error that it could not resolve because I’m expecting a string and the value is an object. Similarly the bind method failed too.

I have:

Binder binder = foodGrid.getEditor().getBinder();
TextField caloriesTextField = new TextField();
binder.forField(caloriesTextField)
    .withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
    .withConverter(new StringToCaloriesConverter("Must be an integer"))
    .bind(Food::getCalories, Food::setCalories);

This failed at lines 4 and 6.

Your CustomCaloryValidator needs to be of type your StringToCaloriesConverter is converting to.

Firstly the first error in the code was that I had a generic Binder where I should’ve used Binder binder = foodGrid.getEditor.getBinder(). That was a simple error that I should’ve caught. Well it’s one of those that’s obvious in retrospect :frowning:

Anyways I’m still dealing with the same issue. Here is the full code:

Binder<Food> binder = foodGrid.getEditor().getBinder();
TextField caloriesTextField = new TextField();

binder.forField(caloriesTextField)
    .withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
    .withConverter(new StringToCaloriesConverter("Must be an integer"))
    .bind(Food::getCalories, Food::setCalories);

// This line fails with the error
foodGrid.addColumn(Food::getCalories, new NumberRenderer(myNumberFormat))
    .setEditorComponent(new TextField(), Food::setCalories);

The problem is that the type long (setCalories()) does not work with TextField. How do I add the converter to the addColumn call? I assume I need to do this because if I don’t include addColumn my table is empty.

Firstly the main issue was that the Binder did not specify the generic type, it needed to be:

Binder<Food> binder = foodGrid.getEditor().getBinder(); And NOT what I had in my first post:

Binder binder = foodGrid.getEditor().getBinder(); That being said there were several other gotchas. First when you do a forField() you need to keep track of that binding to be able to set it later with the column. This wasn’t clear at all for me. Specifically you need to:

Binder.Binding<Food, Long> caloriesBinder = binder.forField(caloriesTextField)
        .withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
        .withConverter(new StringToCaloriesConverter("Must be an integer"))
        .bind(Food::getCalories, Food::setCalories);

I’m not 100% sure on the caloriesBinder because my code is different and this is an example, but you need that binding. You then take that binding and do:

foodGrid.getColumn("calories").setEditorBinding(caloriesBinding); This allows the correct editor to work. This is in the documentation but the example is very simple so I missed that. The other thing is that the documentation just seems to have Binding<Todo, Boolean> but that didn’t work for me, I had to do Binder.Binding<Todo, Boolean> for the example to work for me. Not sure why…

The next step which is extremely important depending on what you’re displaying, is to add a renderer otherwise you can run into some weird issues. For example if you’re using long to store a currency then you need to convert it to display a currency amount. Similarly if you’re using a date then you probably also want to format it. You then need to add a renderer. The only way I could find how to do it without compilation errors (mismatched types) was:

((Grid.Column<Food, Long>)foodGrid.getColumn("calories")).setRenderer(new CaloriesRenderer()); Just for completeness you then need to enable the editor with:

foodGrid.getEditor().setEnabled(true); Lastly, if the table is part of a bigger bean then you need to call foodGrid.setItems(), you cannot just rely on binder.readBean() because it cannot accept a list. So for example if instead of food the bean was a meal which consisted of a number of ingredients, then you could not do binder.readBean(meal) nor could you do binder.readBean(meal.getIngredients) even though you can do binder.readBean(meal) for the rest of the form. The only way I could make it work was to do:

binder.readBean(meal);
foodGrid.setItems(meal.getIngredients);

I assume there’s a better way without needing both of these lines but I couldn’t find it…