twinColumn

twinColumn lets users select items by moving them between available and selected columns.

XML Element

twinColumn

Java Class

TwinColumn

Basics

The component puts two columns side by side. The left column contains items that the user can select from. The right column displays currently selected items. Users can select one or more items and click buttons to move them between columns, adding or removing them from the selection.

To create the component, use twinColumn XML element and set its itemsContainer attribute to a collection container. The items within this container will appear in the columns.

The following example demonstrates how a basic twin column is created:

<data readOnly="true">
    <instance id="productDc"
              class="io.jmix.uisamples.entity.Product"
              fetchPlan="_local">
    </instance>
    <collection id="productTagsDc"
                class="io.jmix.uisamples.entity.ProductTag"
                fetchPlan="_local">
        <loader id="productTagsDl" readOnly="true">
            <query>
                <![CDATA[select e from ProductTag e order by e.name]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
    <twinColumn id="twinColumn" label="Tags" itemsColumnLabel="Available tags"
                selectedItemsColumnLabel="Selected tags" itemsContainer="productTagsDc"
                dataContainer="productDc" property="tags"/>

Data-aware twinColumn

Data binding refers to linking a visual component to a data container. Changes in the visual component or corresponding data container can trigger updates to one another. See Using Data Components for more details.

To create twinColumn connected to data, use the dataContainer and property attributes. The itemsContainer attribute is used to create a list of items.

XML
<data readOnly="true">
    <instance id="productDc"
              class="io.jmix.uisamples.entity.Product"
              fetchPlan="_local">
    </instance>
    <collection id="productTagsDc"
                class="io.jmix.uisamples.entity.ProductTag"
                fetchPlan="_local">
        <loader id="productTagsDl" readOnly="true">
            <query>
                <![CDATA[select e from ProductTag e order by e.name]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
    <twinColumn id="twinColumn" label="Tags" itemsColumnLabel="Available tags"
                selectedItemsColumnLabel="Selected tags" itemsContainer="productTagsDc"
                dataContainer="productDc" property="tags"/>
Java
@ViewComponent
protected InstanceContainer<Product> productDc;
@ViewComponent
protected Span spanValue;

@Autowired
protected Metadata metadata;

@Subscribe
protected void onInit(InitEvent event) {
    Product product = metadata.create(Product.class);
    productDc.setItem(product);
}

@Subscribe("twinColumn")
protected void onTwinColumnValueChange(ComponentValueChangeEvent<TwinColumn<Product>, Product> event) {
    if (productDc.getItem().getTags() == null) {
        return;
    }

    spanValue.setText(getSelectedTagsInstanceName());
}

protected String getSelectedTagsInstanceName() {
    return productDc.getItem().getTags()
            .stream()
            .map(ProductTag::getInstanceName)
            .collect(Collectors.joining(", "));
}

Multi Select

The twinColumn component is always in multi-select mode, allowing users to select and move multiple items. You can also provide the ability to move all items at once by setting the selectAllButtonsVisible attribute:

@ViewComponent
protected TwinColumn<String> twinColumn;
@Subscribe("selectAllButtonsCheckbox")
public void onSelectAllButtonsCheckboxValueChange(ComponentValueChangeEvent<JmixCheckbox, Boolean> event) {
    twinColumn.setSelectAllButtonsVisible(event.getValue());
}

Column Labels

You can provide descriptive labels for each column with the itemsColumnLabel and selectedItemsColumnLabel attributes:

<twinColumn id="twinColumn" label="Shopping list" itemsColumnLabel="Need to buy"
            selectedItemsColumnLabel="Purchased"/>

Items Order

By default, items do not maintain their original position in the list. Each time an item is moved to another column, it is added to the bottom of the list. You can choose to preserve the original order of items at all times by setting reorderable = "true".

@ViewComponent
protected TwinColumn<String> twinColumn;
@Subscribe("reorderableCheckbox")
public void onReorderableCheckboxValueChange(ComponentValueChangeEvent<JmixCheckbox, Boolean> event) {
    twinColumn.setReorderable(event.getValue());
}

Custom Items

Populate twinColumn programmatically from a list, a value-to-label map, or an enumeration.

XML
<twinColumn id="twinColumnWithList"
            label="Items List"/>
<twinColumn id="twinColumnWithMap"
            label="Items Map"/>
<twinColumn id="twinColumnWithEnum"
            label="Items Enum"/>
Java
@ViewComponent
protected TwinColumn<Integer> twinColumnWithList;
@ViewComponent
protected TwinColumn<Integer> twinColumnWithMap;
@ViewComponent
protected TwinColumn<CustomerGrade> twinColumnWithEnum;

@Subscribe
protected void onInit(InitEvent event) {
    twinColumnWithList.setItems(getItemsList());
    ComponentUtils.setItemsMap(twinColumnWithMap, getItemsMap());
    twinColumnWithEnum.setItems(CustomerGrade.class);
}

protected List<Integer> getItemsList() {
    return List.of(2, 4, 5, 7);
}

protected Map<Integer, String> getItemsMap() {
    Map<Integer, String> itemsMap = new LinkedHashMap<>();
    itemsMap.put(2, "Two");
    itemsMap.put(4, "Four");
    itemsMap.put(5, "Five");
    itemsMap.put(7, "Seven");
    return itemsMap;
}

Theme Variants

Use the themeNames attribute to apply one or more theme variants.

Variant Description Supported By

no-border

Removes the outer border of the component.

Aura, Lumo

no-row-border

Removes the separators between rows.

Lumo

checkmarks

Uses checkmarks to indicate selected items instead of changing the row background color.

Lumo

no-spaces-between-actions

Removes the space between action buttons.

Aura, Lumo

Attributes

The following attributes are specific to twinColumn:

Name Description Default

itemsColumnLabel

Sets the items column label. See Column Labels.

itemsContainer

Sets the items container. See Basics.

reorderable

Controls whether users can reorder items in the component. See Items Order.

selectAllButtonsVisible

Controls whether buttons for selecting and clearing all items are displayed. See Multi Select.

selectedItemsColumnLabel

Sets the selected items column label. See Column Labels.

The following shared attributes are supported by twinColumn:

Handlers

The following handlers are specific to twinColumn:

Name Description

validator

Validates the component value.

The following shared handlers are supported by twinColumn:

Elements

A twinColumn can include validator as its nested elements.