Reputation: 332
I am currently using Vaadin 7.3+ and want to validate in a text field as the user types in real time.
This is what I tried so far:
textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
@Override
public void textChange(FieldEvents.TextChangeEvent event) {
for (Validator v : textField.getValidators()) {
try {
v.validate(event.getText());
} catch (InvalidValueException e) {
log.warn("validation error: " + e.getMessage() + " and value was: {}", event.getText());
}
}
}
});
The problem is that although all the validators are being executed and validation is being done the red error indicator is not rendered until the focus leaves the field, i.e. the user hits enter or clicks somewhere else. I tried adding textField.markAsDirty
but this did not work. Does anyone know of a solution to this problem? Or of a better solution in general for creating a real time validator on a text field?
Thanks in advance for your time and input :-)
Upvotes: 4
Views: 6047
Reputation: 78
Take a look in the Vaadin Documentation. If I get you right it should be fine to set your field in immediate mode. Sometimes it is recommend to allow null values to avoid unnecessary warnings.
TextField field = new TextField("Name");
field.addValidator(new StringLengthValidator(
"The name must be 1-10 letters (was {0})",
1, 10, true));
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(true);
Upvotes: 0
Reputation: 1934
Validators in core the Vaadin are not designed to work while typing, which is a shame for a RIA framework. This will hopefully be fixed in upcoming version. Making it work well today with core components is bit tricky, but doable. Your own solution probably has some UX issues if there is some latency between your server and the client - the cursor might jump into unintended place if user starts to retype again while validator is executed. I have worked on this a lot in Viritin add-on. By using its AbstractForm (or raw MBeanFieldGroup) together with MTextField this should work pretty well and without any configuration. You can try that solution with e.g. this example.
Upvotes: 2
Reputation: 332
This straight forward workaround solution seems to work fine although it is quite inelegant.
textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
@Override
public void textChange(FieldEvents.TextChangeEvent event) {
try {
textField.setValue(event.getText());
// workaround cursor position problem
textField.setCursorPosition(event.getCursorPosition());
textField.validate();
} catch (InvalidValueException e) {
log.warn("validation error: " + e.getMessage() + " and value was: {}", delegate.getValue());
}
}
});
Upvotes: 1
Reputation: 37008
the problem here is, that the event sends the text, but does not actually modify the value of the input. the easiest way to go around this would be setting the value. e.g.
addTextChangeListener(new FieldEvents.TextChangeListener() {
@Override
void textChange(FieldEvents.TextChangeEvent event) {
final textField = event.source as TextField
textField.value = event.text
}
})
this would just trigger the change of the field and also the validators and all will go down to the client as expected.
as you stated in the comments, the cursor pos should be kept. You can just validate the text from the event with whatever means you need. Key point here is, to just set the componentError
of the field to get the error down the line for the field.
@Override
void textChange(FieldEvents.TextChangeEvent event) {
final tf = event.source as TextField
try {
tf.validate(event.text) // this works in groovy! not java.
tf.setComponentError(null)
}
catch (InvalidValueException e) {
tf.setComponentError(new SystemError(e))
}
}
Upvotes: 1