Cribber
Cribber

Reputation: 2943

Vaadin 14 Textfield format with thousand separators while typing

I'm using Vaadin 14 + Java and I want to display a textfield with monetary values including thousands separators while typing.

The separators get displayed if I load the object into my form and the textfield, but whenever I type a new value or change the existing value, the thousand-seperators doesn't show up / does not update until I saved the object to the database and got the object again.

I set the ValueChangeMode already EAGER, but I suppose the converter only gets applied when writing / loading from the database.

How can I insert/update thousand-separators on the fly while typing?

Example: When i type "1000000", I want the textfield to update to "1.000" after I typed the third zero, and to "10.000" after the next one, then "100.000" and finally "1.000.000" after the sixth and last zero.

Textfield:

money_tf = new TextField("Money in €");
money_tf.setSuffixComponent(new Span("€"));
money_tf.addThemeVariants(TextFieldVariant.LUMO_ALIGN_RIGHT);
money_tf.setValueChangeMode(ValueChangeMode.EAGER);

Binder

binder = new BeanValidationBinder<>(MyClass.class);
binder.forField(money_tf).withConverter(new PriceConverter()).bind("money");

my PriceConverter:

private static class PriceConverter extends StringToBigDecimalConverter {

    public PriceConverter() {
        super(BigDecimal.ZERO, "Cannot convert to decimal value.");
    }

    @Override
    protected NumberFormat getFormat(Locale locale) {

        final NumberFormat format = super.getFormat(locale);
        format.setGroupingUsed(true); // enabled thousand separators
        if (format instanceof DecimalFormat) {
            // Always display currency with two decimals
            format.setMaximumFractionDigits(2); 
            format.setMinimumFractionDigits(2);
        }
        return format;
    }
}

Upvotes: 2

Views: 1641

Answers (1)

Tatu Lund
Tatu Lund

Reputation: 10643

I set the ValueChangeMode already EAGER, but I suppose the converter only gets applied when writing / loading from the database.

This works, but server round trip is involved. If you do not have set-up automatic commit of every change to backend, the database is not update on every letter, only when you call explicitly binder.writeBean(..) and commit the changes to database. In fast typing on slow networks the user experience may not be the best possible.

How can I insert/update thousand-separators on the fly while typing?

I understand your question as, can the conversion be done in the client side, i.e. Browser. And the answer is yes. For simple cases you can use textField.setPattern(regexp) where regexp is a String with regular expression pattern. For more complex scenarios it requires of course some JavaScript logic, but do not worry, there is TextField Formatter add-on in the Directory, that wraps Cleave JS library and gives you nice Java API for this purpose.

Alternatively you can use BigDecimalFieldField component of the framework, which also limits the input to certain number format. The value type of that field is not String, but BigDecimal.

Upvotes: 0

Related Questions