multiSelectComboBox 多选下拉框

multiSelectComboBox 支持用户从下拉列表选择一项或多项。该组件与 comboBox 类似。

XML 元素

multiSelectComboBox

Java 类

JmixMultiSelectComboBox

基本用法

当用户点击控件时可以打开下拉列表。使用键盘的上下键或者在控件中输入内容也可以打开下拉列表。

XML
<multiSelectComboBox id="multiSelectComboBox"/>
<multiSelectComboBox itemsEnum="io.jmix.uisamples.entity.Day" clearButtonVisible="true" width="17em"/>
Java
@ViewComponent
protected JmixMultiSelectComboBox<String> multiSelectComboBox;

@Subscribe
protected void onInit(InitEvent event) {
    multiSelectComboBox.setItems("CSS", "HTML", "Java", "JavaScript", "JSON", "Kotlin", "XML");
    multiSelectComboBox.select("Java", "Kotlin");
}

数据感知的 multiSelectComboBox

数据绑定是指将组件与 数据容器 进行关联。可视化组件或相应数据容器中的更改可以触发彼此的更新。有关详细信息,请参阅 使用数据组件。

multiSelectComboBox 专为存储多个值的属性而设计。当该组件绑定实体属性时,属性类型应为集合,例如 List 或 Set。

最常见的用例是为多对多关联选择相关实体:

Hobby.java
@JmixEntity
@Table(name = "HOBBY")
@Entity
public class Hobby {
    /* attributes */
}
User.java
@JmixEntity
@Entity
@Table(name = "USER_")
public class User {

    /* other attributes */

    @JoinTable(name = "USER_HOBBY_LINK",
            joinColumns = @JoinColumn(name = "USER_ID"),
            inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
    @ManyToMany
    private List<Hobby> userHobbies;
}

此时,multiSelectComboBox 支持用户选择多个 Hobby 实例,并且该对应关系存储在连接表中。

如需创建数据感知的 multiSelectComboBox,请使用 dataContainer 和 property 属性将组件绑定到集合属性。使用 itemsContainer 属性提供可用项列表。以下示例生成一个数据感知的 multiSelectComboBox。

XML
<data>
    <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">
            <query>
                <![CDATA[select e from ProductTag e]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
<layout>
    <multiSelectComboBox id="multiSelectComboBox" width="15em" label="Product tags"
                         dataContainer="productDc" property="tags"
                         itemsContainer="productTagsDc"/>
    <hbox>
        <span text="Value in the container:"/>
        <span id="spanValue"/>
    </hbox>
</layout>
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("multiSelectComboBox")
protected void onMultiSelectComboBoxFieldValueChange(
        TypedValueChangeEvent<JmixMultiSelectComboBox<Product>, Product> changeEvent) {
    spanValue.setText(getSelectedTagsInstanceName());
}

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

itemsContainer 定义下拉框中可用的选项。用户选择的值保存在 dataContainer 和 property 指定的集合属性中。

组件的值包含所选的条目。当组件绑定集合属性时,Jmix 会将选定的条目转换为属性集合类型,例如 List 或 Set。

使用 MetaClass

使用 multiSelectComboBox 时,还可以不直接指定关联的数据,即无需设置 dataContainer 或 property 属性。此时,需要使用 metaClass 属性指定实体类型。itemsContainer 属性指定选项实例的集合。

例如,组件可以使用 Hobby 实体,其元数据类为 Hobby。

<multiSelectComboBox metaClass="Hobby"
                     itemsContainer="userHobbiesDc"/>

通用下拉列表功能

multiSelectComboBox 支持常规 comboBox 的功能:

自定义选项标签

通过 itemLabelGenerator 控制如何显示选项的文本:

XML
<data>
    <collection id="productTagsDc"
                class="io.jmix.uisamples.entity.ProductTag"
                fetchPlan="_local">
        <loader id="productTagsDl">
            <query>
                <![CDATA[select e from ProductTag e]]>
            </query>
        </loader>
    </collection>
</data>
    <multiSelectComboBox id="multiSelectComboBox" label="Product tags" itemsContainer="productTagsDc"/>
Java
@Install(to = "multiSelectComboBox", subject = "itemLabelGenerator")
protected String multiSelectComboBoxItemLabelGenerator(ProductTag productTag) {
    return "#" + productTag.getName();
}

自定义选项渲染器

还可以为每个选项提供一个组件以显示更丰富的内容。下面的示例中使用图标和名称显示每个枚举值:

XML
<multiSelectComboBox id="iconsMultiSelectComboBox" clearButtonVisible="true"
          label="Icons"
          width="20em"/>
Java
@ViewComponent
protected JmixMultiSelectComboBox<VaadinIcon> iconsMultiSelectComboBox;

@Autowired
protected UiComponents uiComponents;

@Subscribe
protected void onInit(InitEvent event) {
    iconsMultiSelectComboBox.setItems(VaadinIcon.values());
}

@Supply(to = "iconsMultiSelectComboBox", subject = "renderer")
protected Renderer<VaadinIcon> multiSelectComboBoxComponentRenderer() {
    return new ComponentRenderer<>(vaadinIcon -> {
        HorizontalLayout contentBox = uiComponents.create(HorizontalLayout.class);
        contentBox.setPadding(false);

        contentBox.add(vaadinIcon.create());
        contentBox.add(vaadinIcon.name());

        return contentBox;
    });
}

自动展开

multiSelectComboBox 可以自动扩展其宽度以容纳表示所选条目的小卡片。仅当所需的扩展方向未定义尺寸时才有效(例如,设置 max-width 会限制组件的宽度,从而无法扩展)。支持的选项:

  • VERTICAL - 组件垂直扩展,小卡片会自动换行。

  • HORIZONTAL - 组件水平扩展直至 max-width 的宽度,然后会折叠溢出的卡片。

  • BOTH - 组件首先水平扩展直至 max-width 的宽度,然后垂直扩展,小卡片会自动换行。

  • NONE - 组件不会扩展,并折叠溢出的卡片。

    == 已选条目置顶

selectedItemsOnTop 属性控制所选条目在选项列表 overlay 中的显示方式。

以下是其工作原理:

  • 如果 selectedItemsOnTop 设置为 true,则已选择的条目将显示在 overlay 的顶部,其他未选择的条目将保留在底部。这种排列方式为用户提供了非常直观的展示,特别是用户需要频繁查看最近选择的条目时。

  • 如果 selectedItemsOnTop 设置为 false(默认值),则所选条目将按其选择顺序显示,而不会移动到 overlay 的顶部。这种排列保持了选择的顺序,当选择的顺序比较重要或与其他 UI 元素的视觉一致性很重要的情况下,可以首选这种排列方式。

选项获取回调

multiSelectComboBox 可以根据用户输入批量加载选项。

例如,当用户输入 foo 时,组件会从数据库中加载最多 50 个名称中包含 foo 的选项,并在下拉列表显示。当用户向下滚动列表时,组件会获取具有相同查询语句的下一批 50 个选项,并将添加到选项列表中。

声明式获取选项

要实现这个功能,需要定义内部的 itemsQuery 元素。

itemsQuery 元素需要在内部的 query 元素中定义 JPQL 查询语句,以及通过几个属性配置如何加载数据:

  • escapeValueForLike - 启用搜索包含特殊符号的值:%、\ 等。默认为 false。

  • searchStringFormat - 一个包含变量占位符的字符串,该占位符在查询时将替换为实际值。

  • class(可选)- 指定需要获取实体类的全限定名称。

  • fetchPlan(可选)- 指定加载数据时需要使用的 fetch plan。

itemsQuery 元素有下列内部元素:

  • query - 定义 JPQL 查询语句的元素。

  • fetchPlan - 可选的描述符,用于定义 fetch plan。

multiSelectComboBox 中配置 itemsQuery 的示例:

<multiSelectComboBox id="declarativeMultiSelectComboBox" label="Customer"
                metaClass="Customer">
    <itemsQuery class="io.jmix.uisamples.entity.Customer"
                searchStringFormat="(?i)%${inputString}%"
                escapeValueForLike="true"
                fetchPlan="_local">
        <query>
            <![CDATA[select e from Customer e where e.name
            like :searchString escape '\' order by e.name asc]]>
        </query>
    </itemsQuery>
</multiSelectComboBox>

itemsQuery 不支持使用 container_ 或 component_ 前缀自动绑定数据容器或可视化组件参数;这个声明式的绑定仅支持 dataLoadCoordinator facet。

编程式获取选项

选项的获取也可以通过 itemsFetchCallback 处理器编程式定义。示例:

@Autowired
protected DataManager dataManager;

protected Collection<Customer> customers;

@Subscribe
protected void onInit(InitEvent event) {
    customers = dataManager.load(Customer.class).all().list();
}

@Install(to = "programmaticMultiSelectComboBox", subject = "itemsFetchCallback")
protected Stream<Customer> programmaticMultiSelectComboBoxItemsFetchCallback(Query<Customer, String> query) {
    String enteredValue = query.getFilter()
            .orElse("");

    return customers.stream()
            .filter(customer -> customer.getName() != null &&
                    customer.getName().toLowerCase().contains(enteredValue.toLowerCase()))
            .skip(query.getOffset())
            .limit(query.getLimit());
}

示例中,数据通过 DataManager 获取,但是也可以自定义一个 service 获取。

验证

如需检查 multiSelectComboBox 组件输入的值,可以通过内部元素 validators 使用 validator。

下面是 multiSelectComboBox 可以使用的预定义验证器:

XML 元素

validators

预定义验证器

custom - notEmpty - notNull - size

样式版本

使用 themeNames 属性配置一个或多个样式。

样式 描述 支持的主题

small

组件尺寸较小

Aura, Lumo

align-left

字段值左对齐

Aura, Lumo

align-center

字段值居中

Aura, Lumo

align-right

字段值右对齐

Aura, Lumo

helper-above-field

帮助文字显示在字段上方,标题下方。

Aura, Lumo

XML 属性

下面是 multiSelectComboBox 的特殊属性:

名称 描述 默认值

allowCustomValue

用户是否可以输入选项中没有的值。

—

autoExpand

当组件没有足够的空间展示选项的小卡片时,使用这个属性控制组件的行为。参阅 自动展开。

NONE

autoOpen

当组件获得焦点时,是否自动展开。

—

clearButtonVisible

组件是否显示一个清除按钮。

false

itemsContainer

设置选项的数据容器。

—

itemsEnum

设置选项的枚举。

—

metaClass

为组件设置一个实体类。如果组件不关联数据容器的话,需要设置改属性。参考 使用 MetaClass。

—

opened

设置下拉列表是否展开。

false

pageSize

设置每页的数量。

—

selectedItemsOnTop

是否在 overlay 顶部显示已选条目的分组。参阅 已选条目置顶。

false

下面是 multiSelectComboBox 支持的其他通用属性:

事件和处理器

下面是 multiSelectComboBox 的特殊事件和处理器:

名称 描述

CustomValueSetEvent

当用户输入自定义内容时触发。

itemLabelGenerator

com.vaadin.flow.component.ItemLabelGenerator 可以自定义某个选项展示给用户的名称。参阅 comboBox 的 itemLabelGenerator 和 在线示例。

itemsFetchCallback

仅在需要时加载选项数据。参阅 选项获取回调。

renderer

用于设置 Renderer,为列表中的每个选项自定义渲染。但这不会改变已选择选项的渲染方式,这可以通过 ItemLabelGenerator 配置。参考 在线示例。

validator

验证组件值。

下面是 multiSelectComboBox 支持的其他通用事件:

XML 内部元素

一个 multiSelectComboBox 可以包含 fragmentRenderer、itemsQuery、tooltip 和 validator 作为其内部元素。

参考