Custom Datatype in v7 - in a table?

I have a custom data type (CurrencyDatatype - YES, I know you have one too :wink: ). I have a special requirement for my field in a table to disable edit under certain circumstances. It all looks like this:

CurrencyDatatype:

@JavaClass(BigDecimal.class)
public class CurrencyDatatype implements Datatype<BigDecimal> {

    private static final String PATTERN = "$###,##0.00";

    @Override
    public Class getJavaClass() {
        return BigDecimal.class;
    }

    @Override
    public String format(@Nullable Object value) {
        if (value == null)
            return "";

        DecimalFormat format = new DecimalFormat(PATTERN);
        return format.format(value);
    }

    @Override
    public String format(@Nullable Object value, Locale locale) {
        return format(value);
    }

    @Nullable
    @Override
    public BigDecimal parse(@Nullable String value) throws ParseException {
        if (Strings.isNullOrEmpty(value))
            return null;

        DecimalFormat format = new DecimalFormat(PATTERN);
        format.setParseBigDecimal(true);
        BigDecimal result;
        try {
            result = (BigDecimal) format.parse(value);
        } catch (ParseException e) {
            try {
                result = new BigDecimal(value);
            } catch (Exception e1) {
                throw new ParseException("Error parsing " + value, 0);
            }
        }
        return result;
    }

    @Nullable
    @Override
    public BigDecimal parse(@Nullable String value, Locale locale) throws ParseException {
        return parse(value);
    }

Entity with a CurrencyDatatype field defined:

    @MetaProperty(datatype = "CurrencyDatatype")
    @Column(name = "AMOUNT")
    private BigDecimal amount;

Table Entry:

<table id="tblOrders" dataContainer="itemsDc"
     caption="Orders (Click on a row to see the Order Lines below)" editable="true"
     height="100%" width="100%">
     <columns>
         <column id="amount" editable="true"/>
     </columns>
 </table>

I want to disable that editable=“true” under certain circumstances. The way I did that in v6 was to use a generated column. This is my attempt under v7:

    @Subscribe
    public void onBeforeShow(BeforeShowEvent event) {
       tblOrders.addGeneratedColumn("amount", entity -> {
            TextField textField = UiComponents.create(TextField.TYPE_BIGDECIMAL);
            CurrencyDatatype currencyDatatype = new CurrencyDatatype();
            textField.setValue(currencyDatatype.format(entity.getAmount()));
            textField.setValueSource(new ContainerValueSource<>(itemsDc, "amount"));
            if (entity.getLines().size() > 0) {
                textField.setEditable(Boolean.FALSE);
            }
            return textField;
        });

When I execute this, I am getting:

image

This seems to be coming from Vaadin, where it is trying to treat the field as a number but it is now actually a text string. Of course, if I don’t use a custom formatter, then it works fine, but my field does not have a left-justified dollar sign as I require.

What is the correct v7 way to do this?

Hi Eric,

With uiComponents.create(TextField.TYPE_BIGDECIMAL) you create a field that accepts a BigDecimal value. Use parametrization of types, then the compiler will help you:

TextField<BigDecimal> textField = uiComponents.create(TextField.TYPE_BIGDECIMAL);

You would get this variable type automatically if you used Refactor > Extract > Variable when cursor is on the expression.

In order to set string value to the field, just use TextField.TYPE_STRING.

Regards,
Konstantin

Yep, this much I already know. My problem is that, in the regular case, when your code displays a TextField based on my CurrencyDatatype, it is able to call my parse function when you enter data to it to get the BigDecimal back out, and it is able to call my format function to add the currency character. It all just magically happens.

However, when I go to create my own TextField based on that same database entity attribute (declared as a CurrencyDatatype), I get the error. This is because I can’t say:

TextField<CurrencyDatatype> textField = uiComponents.create(Textfield.TYPE_CURRENCYDATATYPE);

There is no such thing.

How do I duplicate what you do when you display/enter a custom data type?

Good question.
Create the field with type which is the underlying Java type of your datatype, in your case it is BigDecimal. Then assign your datatype to the field:

@Inject
private DatatypeRegistry datatypeRegistry;

@Subscribe
private void onInit(InitEvent event) {
    TextField<BigDecimal> field = uiComponents.create(TextField.TYPE_BIGDECIMAL);
    field.setDatatype(datatypeRegistry.get("currency"));
    field.setValue(new BigDecimal("123.456"));
    getWindow().add(field);

    field.addValueChangeListener(valueChangeEvent -> {
        notifications.create().withCaption("Value: " + valueChangeEvent.getValue()).show();
    });
}