Hi!
I stumbled upon a little problem where I want to use a wrapper to delegate TextFields in order to dynamically validate input from the user in a table.
I assign an IntegerRangeValidator and set a StringToIntegerConverter to my TextField and provide this TextField to the wrappers constructor (this happens in the createField()-method). Inside the wrapper, the TextField is set to an instance object. The converter is still there. The wrapper then overrides the TextChangeListeners textChange()-method and validates the users input.
The problem comes when the validation is at hand. The converter is suddenly gone (null) from the TextField object and there is no conversion from String to Integer, whereupon the validation process fails (because an IntegerRangeValidator naturally cannot validate a String).
Why does the converter disappear?
I did check the TextField that is being validated and it still has the same object id as the “original” TextField but, as I mentioned, the converter is now set to null.
The createField-method:
@Override
public Field<?> createField(Container container, Object itemId, Object propertyId, com.vaadin.ui.Component uiContext) {
TextField tField = null;
tField = (TextField) super.createField(container, itemId, propertyId, uiContext);
tField.setBuffered(true);
addFieldListeners(tField);
if (propertyId.equals("age") {
tField.setRequired(true);
tField.setRequiredError("This field is required!");
tField.setConverter(new StringToIntegerConverter());
tField.addValidator(new IntegerRangeValidator("Only Integers allowed!", 1, 150));
@SuppressWarnings({ "unchecked", "rawtypes" })
TableDataValidatingWrapper<TextField> wField = new TableDataValidatingWrapper(tField);
return wField;
} else {
return null;
}
}
The wrapper:
public class TableDataValidatingWrapper<T> extends CustomField<T> {
private static final long serialVersionUID = 1L;
protected Field<T> delegate;
public TableDataValidatingWrapper(final Field<T> delegate) {
this.delegate = delegate;
if (delegate instanceof TextField) {
final TextField textField = (TextField) delegate;
textField.setTextChangeEventMode(AbstractTextField.TextChangeEventMode.TIMEOUT);
textField.setTextChangeTimeout(200);
textField.setCaption("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
private static final long serialVersionUID = 1L;
@Override
public void textChange(FieldEvents.TextChangeEvent event) {
try {
textField.setValue(event.getText());
textField.validate();
} catch (EmptyValueException e) {
System.out.println("Caught exception " + e);
} catch (InvalidValueException e) {
System.out.println("Caught exception " + e);
} catch (Exception e) {
System.out.println("Caught unknown exception " + e);
}
}
});
}
}
// ... some other overridden methods
}
I extracted all the variables that are changed…
This is the TextField
before
validation:
val$textField TextField (id=413)
changingVariables false
connectorId null
converter StringToIntegerConverter (id=470)
dataSource null
isFiringTextChangeEvent false
isListeningToPropertyEvents false
lastKnownCursorPosition 0
lastKnownTextContent null
parent null
value “” (id=468)
This is the TextField when the validation occurs:
source TextField (id=413)
changingVariables true
connectorId “55” (id=550)
converter null
dataSource IndexedContainer$IndexedContainerProperty (id=551)
isFiringTextChangeEvent true
isListeningToPropertyEvents true
lastKnownCursorPosition 2
lastKnownTextContent “61” (id=548)
parent FormLayout (id=554)
value “6” (id=553)