entityComboBox 实体下拉框

entityComboBox 支持用户从下拉列表中选择单一 实体 实例并进行相关操作。

XML 元素

entityComboBox

Java 类

EntityComboBox

Basics

当字段值是实体对象时,通常使用 entityComboBox 组件。支持用户选择特定实体实例并执行相关操作。

点击控件或箭头按钮可以打开一个显示实体实例的下拉框。

请注意,除非您配置了懒加载,否则该组件会将选项中所有实例的列表加载到浏览器的内存和服务器的内存中。这可能会消耗更多系统资源,特别是加载大量选项时,甚至会影响性能。此外,选项过多也会让用户难以找到特定的实例。

如果选项过多,例如几千或更多,又或者在选择实例时需要提供更多的信息,那么建议使用 entityPicker。

下面的示例中,使用 entityCombobox 组件选择用户所属的部门:

<data>
    <instance id="orderDc"
              class="io.jmix.uisamples.entity.Order">
        <fetchPlan extends="_local">
            <property name="customer" fetchPlan="_local"/>
        </fetchPlan>
    </instance>
    <collection id="customersDc"
                class="io.jmix.uisamples.entity.Customer"
                fetchPlan="_local">
        <loader id="customersDl">
            <query>
                <![CDATA[select e from Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
<layout>
    <entityComboBox dataContainer="orderDc"
                    itemsContainer="customersDc"
                    property="customer"
                    width="15em"
                    label="With actions">
        <actions>
            <action id="lookup" type="entity_lookup"/>
            <action id="clear" type="entity_clear"/>
        </actions>
    </entityComboBox>
    <entityComboBox dataContainer="orderDc"
                    itemsContainer="customersDc"
                    property="customer"
                    width="15em"
                    label="Without actions"/>
</layout>

有关 entityComboBox 及其变体的更多交互式示例,请参阅:

数据感知的 entityComboBox

使用 dataContainer 和 property 属性将 entityComboBox 与一个实体属性绑定。数据容器提供实体实例,property 表示需要使用该组件编辑的属性,而 itemsContainer 提供实体选项。

选择一个实体

如果只是简单的需要选择一个实体实例,那么可以通过 metaClass 属性指定实体。如果需要从一组特定的实体实例中选择,则可以通过 itemsContainer 属性指定。

<entityComboBox metaClass="Department"
                itemsContainer="departmentsDc">
    // ...
</entityComboBox>

更新实体引用属性

选择实体实例通常用来更新另一个实体中的一个属性。在 上面的示例 中,通过选择 Department 实例更新了 User 实例中的部门属性。

此时,需要将组件绑定至父实体的数据容器,并指定需要更新的属性,这两个步骤分别通过 dataContainer 和 property 属性实现。通过 itemsContainer 属性指定选项列表。

<entityComboBox dataContainer="userDc"
                property="department"
                itemsContainer="departmentsDc">
    // ...
</entityComboBox>

操作

entityComboBox 初始化时并不带任何操作,需要显式地添加,示例:

<data>
    <instance id="orderDc"
              class="io.jmix.uisamples.entity.Order">
        <fetchPlan extends="_local">
            <property name="customer" fetchPlan="_local"/>
        </fetchPlan>
    </instance>
    <collection id="customersDc"
                class="io.jmix.uisamples.entity.Customer"
                fetchPlan="_local">
        <loader id="customersDl">
            <query>
                <![CDATA[select e from Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
<layout>
    <entityComboBox dataContainer="orderDc"
                    itemsContainer="customersDc"
                    property="customer"
                    width="15em"
                    label="With actions">
        <actions>
            <action id="lookup" type="entity_lookup"/>
            <action id="clear" type="entity_clear"/>
        </actions>
    </entityComboBox>
    <entityComboBox dataContainer="orderDc"
                    itemsContainer="customersDc"
                    property="customer"
                    width="15em"
                    label="Without actions"/>
</layout>

如需在 Jmix Studio 中添加 action,可以在视图 XML 或者 Jmix UI 结构面板中选择组件,然后在组件面板点击 Add→Action 按钮。

自定义和预定义操作的详细信息请参阅 entityPicker 的 操作 部分。

延迟加载

该组件支持根据用户输入批量加载选项,而不是一次加载全部选项。这样可以确保流畅的用户体验,即便选项数量非常庞大。

声明式获取选项

若要在视图 XML 中实现延迟加载,需要配置 itemsQuery 属性,而不是 itemsContainer。例如,要最多加载 30 个选项并在列表中显示,可按照下列代码:

<layout>
    <tabSheet id="tabSheet" width="100%">
        <tab id="declarativeTab" label="Declaratively">
            <entityComboBox id="declarativeEntityComboBox" label="Customer"
                            metaClass="Customer">
                <actions>
                    <action id="entityLookup" type="entity_lookup"/>
                    <action id="entityClear" type="entity_clear"/>
                </actions>
                <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>
            </entityComboBox>
        </tab>
        <tab id="programmaticTab" label="Programmatic">
            <entityComboBox id="programmaticEntityComboBox" label="Customer"
                            metaClass="Customer">
                <actions>
                    <action id="entityLookup" type="entity_lookup"/>
                    <action id="entityClear" type="entity_clear"/>
                </actions>
            </entityComboBox>
        </tab>
    </tabSheet>
</layout>

JPQL 查询语句指定要加载的选项。

pageSize 属性定义从数据库加载数据时的批处理大小。默认值为 50。

itemsQuery 中的属性提供对获取数据过程的控制。如下:

  • class – 指定要获取其实例的实体类的全限定名。

  • searchStringFormat – 包含变量占位符的字符串,该占位符随后会被替换为实际值。

  • escapeValueForLike – 指定是否搜索包含特殊符号的值。默认情况下,该值为 false。

  • fetchPlan – 可选的內联 fetch plan。

  • byInstanceName – 如果为 true,则按实例名称查找选项,不需要 JPQL 查询。请参见下文。

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

按实例名称查询

Jmix 3.1+

如需按 实例名称 查找选项,则设置 byInstanceName 属性为 true,并省略查询语句:

<entityComboBox metaClass="User">
    <itemsQuery class="com.company.onboarding.entity.User"
                byInstanceName="true"/>
</entityComboBox>

组件查找其实例名称属性(String 类型)包含输入文本的实例,忽略大小写。适用于任何数据存储,包括自定义数据存储中的 DTO 实体。此模式下不使用 searchStringFormat 和 escapeValueForLike 属性。默认 fetch plan 为 _instance_name。

编程式获取选项

选项的加载过程也可以通过代码在 itemsFetchCallback 处理方法中配置。示例:

XML
<layout>
    <tabSheet id="tabSheet" width="100%">
        <tab id="declarativeTab" label="Declaratively">
            <entityComboBox id="declarativeEntityComboBox" label="Customer"
                            metaClass="Customer">
                <actions>
                    <action id="entityLookup" type="entity_lookup"/>
                    <action id="entityClear" type="entity_clear"/>
                </actions>
                <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>
            </entityComboBox>
        </tab>
        <tab id="programmaticTab" label="Programmatic">
            <entityComboBox id="programmaticEntityComboBox" label="Customer"
                            metaClass="Customer">
                <actions>
                    <action id="entityLookup" type="entity_lookup"/>
                    <action id="entityClear" type="entity_clear"/>
                </actions>
            </entityComboBox>
        </tab>
    </tabSheet>
</layout>
Java
@Autowired
protected DataManager dataManager;

protected Collection<Customer> customers;

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

@Install(to = "programmaticEntityComboBox", subject = "itemsFetchCallback")
protected Stream<Customer> programmaticEntityComboBoxItemsFetchCallback(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 获取,但是也可以修改为通过自定义服务获取。

自定义渲染器

默认情况下,下拉框中的实体实例是以纯文本进行显示。可以自定义渲染器,实现下拉框选项的渲染逻辑,比如可以包含组件、图标、甚至布局。

例如,定义下面的渲染器在部门名称前添加一个图标:

@Supply(to = "customRendererField", subject = "renderer")
private Renderer<Department> departmentRenderer() {
    return new ComponentRenderer<>(department -> {
        Icon icon = VaadinIcon.USERS.create();
        HorizontalLayout contentBox = uiComponents.create(HorizontalLayout.class);
        contentBox.setPadding(false);
        contentBox.add(icon);
        contentBox.add(department.getName());
        return contentBox;
    });
}

或者,可以使用内部的 fragmentRenderer 元素来渲染条目。有关详细信息,请参阅 Fragment 渲染器 部分。

样式版本

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

样式 描述 支持的主题

align-left

字段值左对齐。

Aura, Lumo

align-center

字段值居中对齐。

Aura, Lumo

align-right

字段值右对齐。

Aura, Lumo

align-start

根据当前文本方向,将字段值向起始侧对齐。

Aura

align-end

根据当前文本方向,将字段值向末尾侧对齐。

Aura

helper-above-field

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

Aura, Lumo

small

组件更小。

Aura, Lumo

XML 属性

下面是 entityComboBox 的特殊属性:

名称 描述 默认值

allowCustomValue

如果为 true,则允许用户输入不匹配任何选项的字符串值,将触发 CustomValueSetEvent。

—

autoOpen

当组件获得焦点时,是否自动打开选项列表。

—

itemsContainer

设置选项列表数据容器的名称。

—

metaClass

设置元数据类。

—

opened

设置是否打开下拉列表。

—

pageSize

设置每页的数量。

—

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

事件和处理器

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

名称 描述

CustomValueSetEvent

com.vaadin.flow.component.combobox.ComboBoxBase.CustomValueSetEvent 当用户输入一个非空且不匹配任何选项值时发出。

itemLabelGenerator

为每个选项提供显示的文本。

validator

验证组件值。

renderer

为每个选项提供一个渲染组件。参考 自定义渲染器。

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

XML 内部元素

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