We need to support high precision for certain numbers (interest rates) in an application, but we’d still like to show them rounded to 4 decimal places by default.
So, in a table, some cells contain rates in a TextField<BigDecimal> where user can enter a value with any precision, but which shows the value with 4 decimal points. This is done with a custom BigDecimal converter (as documented in this answer).
We also have a simple tooltip (title attribute) in place, showing the exact value (when I say “exact”, there’s of course some upper limit to the scale, currently 16):

These fields have “onblur” AjaxFormComponentUpdatingBehavior, which causes changed value to be immediately saved and the rest of the table updated.
Now, there are two problems:
- If user clicks the field, then clicks somewhere else, the rounded (4
decimal) value gets updated in domain object & persisted without the
user even realising she changed anything. I.e., the exact value gets lost. - Somewhat trickier: I’d like to make editing the exact value easy.
I.e., when the textfield is clicked (focused), it should change to
show the exact value so user can easily edit that (and not the
rounded value).
As a hacky fix to #1 I changed the setter of the underlying DTO so that it doesn’t actually change the value if the incoming new value is the same but with smaller scale. But I’m looking for something that solves #2 (which would automatically take care of #1 too).
final TextField<BigDecimal> field;
BigDecimal interestRate = ...; // current exact value from the model object
field.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
// something I could do here? using e.g.
// field.setModelObject(), field.setConvertedInput()
// or field.getConverter(BigDecimal.class);
}
}
Having the field, the domain object & the exact BigDecimal value at hand as in above code (executed on every update of the table), what could I do to replace the value visible (editable) in UI?
Could I somehow swap the converter when the field is focused? There isn’t a setter for converter, but perhaps create a custom TextField subclass that allows you to change the converter on the fly…?
As last resort we could change the converter (increase setMaximumFractionDigits) so that the exact values would always be displayed (but that isn’t a solution to this specific problem, it’s merely sidestepping it).
Well, I got it working eventually. Not using pure Wicket, but with a small JavaScript hack.
As mentioned in the question, I already had the exact value in the
titleattribute of the field. So I can just copy the attribute value as the input field’s value.Java:
For these kinds of TextFields, add a Behavior which calls a JS function. Essential method here is
getMarkupId()which returns the (arbitrary, dynamic)<input>element ID that I can use in JS.JavaScript (in a .js file which gets loaded on the relevant Wicket page):
(Note that jQuery is used above; you could of course do this without it too.)
The only problem with this is, at least in our case, a slight delay (maybe 200-500 ms) before the
onUpdate()method gets called, which makes editing the field a little less smooth. (If user changes the value quickly, that change gets overridden by the JS code.)To minimise that annoyance, I only add the Behavior when it is really needed:
Feel free to post better solutions!