Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
Validation failure message for TextField in Grid not shown
Hi,
I created a grid and added a header row to it. In the header row i added textfield for each column (to enable filtering of that column based on the text entered). Columns could be of Non String type (Numeric, Integer, Double, etc). I want that validation error is shown when a user enters a string inside the text field where the column type is non string.
I get InvalidValueException in the console, but nothign on the UI.
for(Grid.Column col : grid.getColumns())
{
com.vaadin.ui.Field field = beanFieldGroup.buildAndBind(null,col.getPropertyId());
if(TextField.class.isAssignableFrom(field.getClass()))
{
((TextField)field).setNullRepresentation("");
((TextField)field).setTextChangeEventMode(AbstractTextField.TextChangeEventMode.LAZY);
((TextField)field).setImmediate(true);
((TextField)field).setValidationVisible(true);
((TextField)field).addTextChangeListener(new FieldEvents.TextChangeListener() {
@Override
public void textChange(FieldEvents.TextChangeEvent event) {
try {
((TextField)field).setValue(event.getText());
// workaround cursor position problem
((TextField)field).setCursorPosition(event.getCursorPosition());
((TextField)field).validate();
} catch (InvalidValueException e) {
((TextField)field).setComponentError(new SystemError(e));
}
}
});
}
filteringHeader.getCell(col.getPropertyId()).setComponent(field);
}
If I am not wrong, I shouldn't even be writing the text listner. Since I have BeanFieldGroup, it should automatically create Validators for the text fields and trigger it.
What am I doing wrong?
thanks for the help,
Chahat
Hi,
Try using a custom field factory and add a custom "number validator" when required. For example:
beanFieldGroup.setFieldFactory(new DefaultFieldGroupFieldFactory() {
@Override
public <T extends Field> T createField(Class<?> dataType, Class<T> fieldType) {
T field = super.createField(dataType, fieldType);
if (Number.class.isAssignableFrom(dataType)) {
field.addValidator(value -> {
if (value != null && !value.toString().isEmpty() && !value.toString().matches("-?\\d+(\\.\\d+)?")) {
throw new InvalidValueException("Please specify a number");
}
});
}
return field;
}
});
Dear Alejandro,
Thanks for your reply. Unfortuntely it leads to same result
The InvalidValueException you throw leads to stacktrace printing on the console
SEVERE:
com.vaadin.data.Validator$InvalidValueException: Could not convert value to Integer
at com.vaadin.ui.AbstractField.validate(AbstractField.java:985)
at com.vaadin.ui.AbstractField.validate(AbstractField.java:960)
at com.aahar.ui.design.grid.GridPanel$2.textChange(GridPanel.java:266)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
However I want to show the User on the UI that the value entered was not a number
for example Like in the sampler example http://demo.vaadin.com/sampler/#databinding/declarative-validation
the fields show error when validation fails.
thanks
Chahat
Could it be because the fields are added to the cols of header row of a grid? Is it possible that Header row is not suppose to show validation errors??
Nope, I tested the code I published and it works. Did you remember to remove the TextChangeListener when trying with my aproach?
Hi Alejandro,
I guess i did remove the TextChangeListner, I have a break point inside the validator, Now the break point is not even hit when i loose focus after entering a wrong value in the textfield. Below is my code
T instance = clazz.getConstructor().newInstance();
final BeanFieldGroup<T> beanFieldGroup = new BeanFieldGroup<T>(clazz);
beanFieldGroup.setItemDataSource(instance);
beanFieldGroup.setFieldFactory( new FieldGroupFieldFactory() {
@Override
public <T extends com.vaadin.ui.Field> T createField(Class<?> dataType, Class<T> fieldType) {
T field = DefaultFieldGroupFieldFactory.get().createField(dataType, fieldType);
if (Number.class.isAssignableFrom(dataType)) {
field.addValidator(value -> {
if (value != null && !value.toString().isEmpty() && !value.toString().matches("-?\\d+(\\.\\d+)?")) {
throw new InvalidValueException("Please specify a number");
}
});
}
return field;
}
});
for(Grid.Column col : grid.getColumns())
{
com.vaadin.ui.Field field = beanFieldGroup.buildAndBind(null,col.getPropertyId());
if(TextField.class.isAssignableFrom(field.getClass()))
{
((TextField)field).setNullRepresentation("");
((TextField)field).setTextChangeEventMode(AbstractTextField.TextChangeEventMode.LAZY);
((TextField)field).setImmediate(true);
((TextField)field).setValidationVisible(true);
}
filteringHeader.getCell(col.getPropertyId()).setComponent(field);
}
I could not create an instance of new DefaultFieldGroupFieldFactory() like you did. Probably different Vaadin versions, but I suppose what I did should have worked as well.
Thanks for the help :)
thanks
Chahat
I'm using Vaadin 7.7.1. Here's the code that worked for me:
beanFieldGroup.setFieldFactory(new DefaultFieldGroupFieldFactory() {
@Override
public <T extends Field> T createField(Class<?> dataType, Class<T> fieldType) {
T field = super.createField(dataType, fieldType);
if (Number.class.isAssignableFrom(dataType)) {
field.addValidator(value -> {
if (value != null && !value.toString().isEmpty() && !value.toString().matches("-?\\d+(\\.\\d+)?")) {
throw new InvalidValueException("Please specify a number");
}
});
}
return field;
}
});
for (Grid.Column col : grid.getColumns()) {
Field<?> field = beanFieldGroup.buildAndBind(null, col.getPropertyId());
filteringHeader.getCell(col.getPropertyId()).setComponent(field);
}
Dear Alejandro,
I was using 7.7.0, I upgraded to 7.7.1
Made a very simple test
VerticalLayout lay = new VerticalLayout();
lay.setSizeFull();
Grid grid = new Grid("Testing");
BeanItemContainer<RecipeList> cont = new BeanItemContainer<>(RecipeList.class);
cont.addAll(stb.getRecipeList());
grid.setContainerDataSource(cont);
grid.setSizeFull();
BeanFieldGroup<RecipeList> beanFieldGroup = new BeanFieldGroup<>(RecipeList.class);
beanFieldGroup.setFieldFactory(new DefaultFieldGroupFieldFactory() {
@Override
public <T extends Field> T createField(Class<?> dataType, Class<T> fieldType) {
T field = super.createField(dataType, fieldType);
if (Number.class.isAssignableFrom(dataType)) {
field.addValidator(value -> {
if (value != null && !value.toString().isEmpty() && !value.toString().matches("-?\\d+(\\.\\d+)?")) {
throw new InvalidValueException("Please specify a number");
}
});
}
return field;
}
});
HeaderRow filteringHeader = grid.addHeaderRowAt(0);
for (Grid.Column col : grid.getColumns()) {
Field<?> field = beanFieldGroup.buildAndBind(null, col.getPropertyId());
filteringHeader.getCell(col.getPropertyId()).setComponent(field);
}
lay.addComponent(grid);
testingTab.setContent(lay);
Everything as you told me to do. I still do not see any error on the UI. The debugger does enter the InvalidValueException, I follwed the code a bit and it seems the code flow does want to communicate the error to the GUI. BUT it doesnt.
Please see attched the GUI screenshot. (FOODID textfield is bound to Integer type)
I would expect the text field with wrong entry to be marked red or something,
It is frustrating to learn you can make it work and I cannot :(
Thanks for the help.
Thanks
Chahat
You are using the "reindeer" theme. Unless, the "valo" theme, I think "reindeer" won't change the look of the field when a validation fails, but you should see a tooltip with the error when the validation fails if you put the mouse pointer over the field.
Hehe Bingo:)
I knew it was some tiny detail we were missing.
Thanks a lot, Bringing the mouse curser I do see the error.
Hi there,
using vaadin 8.0.5 and the Grid row Editor in buffered mode,
bean is not updated when Validator fails, but Editor closes and I see no Error message ...
I expect it to stay open and tell me why validation fails.
final TextField nameEditor = new TextField();
final Binder<Site> binder = grid.getEditor().getBinder();
final Binder.Binding<Site, String> nameBinding = binder
.withValidator( site -> {
System.err.println("VALIDATE name");
return site.getName().length() < 20;·
}, "Name must be less than 20 characters long")
.bind(nameEditor, Site::getName, Site::setName);
grid.addColumn(Site::getName)
.setId("name")
.setCaption("Site Name")
.setEditorBinding(nameBinding);
grid.getEditor().setEnabled(true);
//grid.getEditor().setErrorGenerator((colMap, status) -> {
// System.err.println(" Editor has errors : " + status.hasErrors());
// return "Error String";
//});
grid.getEditor().getBinder().addStatusChangeListener( evt ->
System.err.println("Status Change :" + evt. â–¸ hasValidationErrors()));
grid.getEditor().addSaveListener( evt -> {
System.err.println("SAVE");
try { evt.getBean().save(); }
catch(Exception e) { System.err.println(e.getMessage()); }
});
[java] VALIDATE name
[java] Status Change :true
thanks in advance ;)
Hi, in case you still have the issue. This is a possible implementation that works as expected:
Grid<Site> grid = new Grid<>();
grid.getEditor().setEnabled(true);
grid.getEditor().addSaveListener(t -> t.getBean().save());
TextField name = new TextField("Name");
Binder<Site> binder = grid.getEditor().getBinder();
Binder.Binding<Site, String> binding = binder.forField(name)
.withValidator(new StringLengthValidator("Wrong length", 0, 19))
.bind(Site::getName, Site::setName);
grid.addColumn(Site::getName).setEditorBinding(binding).setEditorComponent(name, Site::setName);
Hi, thanks for your attention, I've tested it and nailed the difference,
using forField(…) is the magic incantation, but then your validator deals with the value of the field
// works
final Binder.Binding<Site, String> binding =
binder.forField(name)
.withValidator(string -> string.length() > 6, "at least 6 chars")
.bind(Site::getName, Site::setName);
as I would prefer to work with my object and simply use one of it's method, the following fails
// does not work
final Binder.Binding<Site, String> binding =
binder
.withValidator(obj -> obj.isValid(), "is not valid")
.bind(name, Site::getName, Site::setName);
using setEditorComponent(…) or not doesn't change anything,
validation is not called at value change.
still .bind(name, Site::getName, Site::setName) calls forField(field).bind(getter, setter);
https://github.com/vaadin/framework/blob/master/server/src/main/java/com/vaadin/data/Binder.java#L1271
there is something fishy under there,
I'll try to investigate more later on.
Keep in mind that the buffered mode won't make the validations until you click "save".