Can I use a generated column as editable on a group table?

If I enable the editable column I get a text box works great. But when I wish to replace this textbox with a combo box the values aren’t stored and when I click a group header to collapse all of the values disappear.

Hello!

This is due to table recreate component when you collapse/expand group header. You need to store value from the component, e.g. in entity property (persistent or transient) and then set this value to the component.

The example below shows how to bind ComboBox with some items to number property of Order entity:

@Autowired
private UiComponents uiComponents;
@Autowired
private GroupTable<Order> ordersTable;

@Install(to = "ordersTable.number", subject = "columnGenerator")
private Component ordersTableNumberColumnGenerator(Order order) {
    ComboBox<String> comboBox = uiComponents.create(ComboBox.NAME);
    comboBox.setOptionsList(List.of("item 1", "item 2"));
    comboBox.setValueSource(new ContainerValueSource<>(ordersTable.getInstanceContainer(order), "number"));
    return comboBox;
}

problem is my transient field is String. And this column will sometimes have strings, numbers or an entity picker…
I can render the entity picker but when I try to get the lookup I get

“IllegalStateException: Range is datatype”

Could you share the code you use to generate entity picker?

When I use something like this, I get not error when opening the lookup screen:

    @Install(to = "citiesTable.someColumn", subject = "columnGenerator")
    private Component citiesTableSomeColumnColumnGenerator(City city) {
        EntityPicker entityPicker = uiComponents.create(EntityPicker.class);
        entityPicker.setMetaClass(metadata.getClass(Country.class));
        Action entityLookupAction = actions.create(EntityLookupAction.ID);
        entityPicker.addAction(entityLookupAction);
        entityPicker.setLookupSelectHandler(collection -> {
            //set selected items into the transient field here
            log.info("Entities selected: {}", collection);
        });
        return entityPicker;
    }

I can generate the field like that… but I have no way of retrieving the value after that… that is why i was binding it to a “STRING” transient field
comboBox.setValueSource(new ContainerValueSource<>(ordersTable.getInstanceContainer(order), “paramValue”));

I cannot make a transient field of java.lang.Object
sometimes i will have text field sometimes number… othertimes an enitity picker.

Instead of setting valueSource to the component you can try to explicitly listen to component value change and explicitly set the value to the UI component based on transient entity property when component is rendered.

Something like this:

    @Install(to = "citiesTable.someColumn", subject = "columnGenerator")
    private Component citiesTableSomeColumnColumnGenerator(City city) {
        EntityPicker<Country> entityPicker = uiComponents.create(EntityPicker.class);
        entityPicker.setMetaClass(metadata.getClass(Country.class));
        Action entityLookupAction = actions.create(EntityLookupAction.ID);
        entityPicker.addAction(entityLookupAction);

        //if "transientString" field is set then we load the entity by the id and set to the entity picker
        if (city.getTransientString() != null) {
            Id<Country> countryId = idSerialization.stringToId(city.getTransientString());
            Country country = dataManager.load(countryId).one();
            entityPicker.setValue(country);
        }

        //when country value is changed write its id to the country field
        entityPicker.addValueChangeListener(countryValueChangeEvent -> {
            Country selectedCountry = countryValueChangeEvent.getValue();
            String serializedCountryId = idSerialization.idToString(Id.of(selectedCountry));
            city.setTransientString(serializedCountryId);
        });
        return entityPicker;
    }

As for different types you have two options here:

  1. Have multiple transient fields - one for integer, one for string, one for entity, etc. Fill the one you need.
  2. Serialize a value of any type to string and work with the values like in the example above.