comboBox 下拉列表

基本用法

comboBox 在用户输入文本时提供对选项值的过滤,以及选项的分页展示。

满足下列情况可以使用 comboBox:

  • 动态过滤。用户需要根据输入的值对选项进行过滤。comboBox 提供了内置的过滤功能。

  • 选项数量大。当选项的数量特别大时,comboBox 可以对选项进行分页,每次仅展示有限的部分选项,以提升渲染性能。

  • 自定义渲染。希望自定义下拉选项的外观,比如可以带有其他信息或样式。comboBox 为自定义选项的渲染方式提供了更大的灵活性。

使用 comboBox 的最简单情况是为实体属性选择枚举值。例如,User 实体具有 OnboardingStatus 枚举类型的 onboardingStatus 属性。

combo box basic
<data>
    <instance class="com.company.onboarding.entity.User" id="userDc"> (1)
        <fetchPlan extends="_base"/> (2)
        <loader id="userDl"/>
    </instance>
</data>
<layout>
    <comboBox id="comboBox"
              label="Onboarding status"
              dataContainer="userDc"
              property="onboardingStatus"/> (3)
</layout>
1 User 实体的 InstanceContainer 容器。
2 容器内实体的内联 fetch plan。
3 将组件与数据容器和属性进行关联。dataContainer 属性使用 userDc 数据容器,property 引用 onboardingStatus 实体属性。

自定义选项

选项列表

comboBox 的选项列表还可以通过 setItems() 方法设置。

首先在 XML 描述中声明组件:

<data>
    <instance class="com.company.onboarding.entity.Step" id="stepDc">
        <fetchPlan extends="_base"/>
        <loader id="stepDl"/>
    </instance>
</data>
<layout>
    <comboBox id="durationComboBox"
              dataContainer="stepDc"
              property="duration"/>
</layout>

然后将组件注入控制器,在 onInit() 方法中设置选项列表:

@ViewComponent
private JmixComboBox<Integer> durationComboBox;

@Subscribe
public void onInit(InitEvent event) {
    durationComboBox.setItems(1,2,3,4,5);
}

组件的下拉列表中会显示 1、2、3、4 和 5。选择的值会设置到 stepDc 数据容器中的 duration 属性上。

选项映射

ComponentUtils.setItemsMap() 可以为每个选项值指定一个字符串标签。

@ViewComponent
private JmixComboBox<Integer> ratingComboBox;

@Subscribe
public void onInit(InitEvent event) {
    Map<Integer, String> map = new LinkedHashMap<>();
    map.put(2, "Poor");
    map.put(3, "Average");
    map.put(4, "Good");
    map.put(5, "Excellent");
    ComponentUtils.setItemsMap(ratingComboBox, map);
}

选项枚举

comboBox 枚举类型的选项可以通过声明式或编程式的方式设置。

itemsEnum 属性定义枚举类作为控件的选项列表。下拉列表中会显示枚举值的本地化名称;组件的值则为枚举的值。

<comboBox label="Onboarding status"
          itemsEnum="com.company.onboarding.entity.OnboardingStatus"/>

下面的示例展示了编程式设置的方法。

@ViewComponent
private JmixComboBox<OnboardingStatus> enumComboBox;

@Subscribe
public void onInit(InitEvent event) {
    enumComboBox.setItems(OnboardingStatus.class);
}

自定义过滤

默认情况下,comboBox 在对选项进行过滤时使用不区分大小写的子串匹配的方法。也就是说,选项会显示任意位置包含用户输入文本的选项,且不分大小写。

如需自定义过滤行为,可以使用 setItems() 方法的第一个参数:

@ViewComponent
private JmixComboBox<String> colorDropDown;

@Subscribe
public void onInit(InitEvent event) {
    List<String> itemsList = List.of("White", "Red", "Blue", "Grey");
    colorDropDown.setItems(getStartsWithFilter(), itemsList);

}
protected ComboBox.ItemFilter<String> getStartsWithFilter() {
    return (color, filterString) ->
            color.toLowerCase().startsWith(filterString.toLowerCase());
}

自定义选项值

comboBox 通过配置可以支持用户输入不在选项列表中的值。

如果 allowCustomValue 属性为 true,用户可以输入不匹配任何选项的字符串值,此时会触发 CustomValueSetEvent。

comboBox 不会自动处理自定义字符串。请使用 CustomValueSetEvent 进行处理。

下面的示例中展示了如何为选项列表添加新的值,并在将来使用:

<comboBox id="colorComboBox"
          label="Select the color"
          allowCustomValue="true"/>
@ViewComponent
private JmixComboBox<String> colorComboBox;

@Subscribe
public void onInit(InitEvent event) {
    colorComboBox.setItems("White", "Red", "Blue", "Grey");
}

@Subscribe("colorComboBox")
public void onColorComboBoxCustomValueSet(CustomValueSetEvent<ComboBox<String>> event) {
    colorComboBox.setValue(event.getDetail());
}

选项获取回调

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

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

声明式配置

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

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

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

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

comboBox 中配置 itemsQuery 的示例:

<comboBox id="userComboBox"
          label="User name"
          pageSize="30"> (1)
    <itemsQuery escapeValueForLike="true"
                searchStringFormat="(?i)%${inputString}%"> (2)
        <query>
            <![CDATA[select e.username from User e where e.username
            like :searchString escape '\' order by e.username asc]]>
        </query>
    </itemsQuery>
</comboBox>
1 组件的 pageSize 选项设置每个请求加载选项的最大数量,默认为 50。
2 可以看到,comboBox 内的 itemsQuery 不需要定义 class 和 fetchPlan 属性,因为查询语句需要返回标量值的一个列表(注意这里使用了 e.name)。如需处理实体,请使用 entityComboBox 组件。

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

编程式配置

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

@Autowired
protected DataManager dataManager;

protected Collection<User> users;

@Subscribe
public void onInit(InitEvent event) {
    users = dataManager.load(User.class).all().list();
}

@Install(to = "programmaticComboBox", subject = "itemsFetchCallback")
private Stream<User> programmaticComboBoxItemsFetchCallback(Query<User, String> query) {
    String enteredValue = query.getFilter()
            .orElse("");

    return users.stream()
            .filter(user -> user.getDisplayName() != null &&
                    user.getDisplayName().toLowerCase().contains(enteredValue.toLowerCase()))
            .skip(query.getOffset())
            .limit(query.getLimit());
}

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

自定义选项标签

itemLabelGenerator 可以自定选项在列表中如何展示,即控制用户看到的文本,从而能够以更友好或特定于上下文的方式显示信息。

@Install(to = "colorComboBox", subject = "itemLabelGenerator")
private String colorComboBoxItemLabelGenerator(String item) {
    return item.toUpperCase();
}

选项渲染

框架提供了自定义选项渲染的功能。可以使用 setRenderer() 方法或 @Supply 注解实现。

<comboBox id="daysComboBox"
          itemsEnum="com.company.onboarding.entity.DayOfWeek"/>
@Supply(to = "daysComboBox", subject = "renderer")
private Renderer<DayOfWeek> daysComboBoxRenderer() {
    return new ComponentRenderer<>(day -> {
        HorizontalLayout layout = uiComponents.create(HorizontalLayout.class);
        layout.setPadding(false);

        String dayValue = metadataTools.format(day);
        H4 label = new H4(dayValue);

        JmixButton button = uiComponents.create(JmixButton.class);
        button.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_TERTIARY_INLINE);
        Icon icon = switch (day) {
            case MONDAY -> VaadinIcon.BRIEFCASE.create();
            case TUESDAY -> VaadinIcon.LINE_CHART.create();
            case WEDNESDAY -> VaadinIcon.TROPHY.create();
            case THURSDAY -> VaadinIcon.GROUP.create();
            case FRIDAY -> VaadinIcon.CASH.create();
            case SATURDAY -> VaadinIcon.GLASS.create();
            case SUNDAY -> VaadinIcon.BED.create();
        };
        button.setIcon(icon);
        layout.add(button, label);
        return layout;
    });
}

Overlay

Overlay 是一个半透明或不透明的图层,用于显示选项的下拉列表。

overlayClass 属性可以为 overlay 元素添加自定义的 CSS 类。

<comboBox id="ratingComboBox"
          datatype="int"
          overlayClass="my-custom-overlay"/>

在 css 文件中自定义样式:

vaadin-combo-box-overlay.my-custom-overlay::part(overlay){
    background-color: #ecfcf9;
    border-radius: 5px;
}

样式版本

使用 themeNames 属性设置组件的样式。

样式 描述 支持的主题

small

组件较小

Aura, Lumo

align-left

字段值左对齐

Aura, Lumo

align-center

字段值居中

Aura, Lumo

align-right

字段值右对齐

Aura, Lumo

helper-above-field

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

Aura, Lumo

验证

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

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

XML 元素

validators

预定义验证器

custom - decimalMax - decimalMin - digits - doubleMax - doubleMin - email - max - min - negativeOrZero - negative - notBlank - notEmpty - notNull - positiveOrZero - positive - regexp - size

XML 属性

通用属性 对所有组件都是一样的配置。 下面是 comboBox 的特殊属性:

名称

描述

默认值

allowCustomValue

如果 allowCustomValue 属性为 true,用户可以输入不匹配任何选项的字符串值,此时会触发 CustomValueSetEvent。参阅 自定义值。

false

autoOpen

当 autoOpen 属性设置为 true 时,comboBox 的下拉列表会在控件获得焦点(鼠标点击或手指点击)时或用户输入内容时自动展示。设置为 false 禁用该功能。

true

itemsEnum

itemsEnum 属性为选项列表定义一个枚举类。参阅 选项枚举。

overlayClass

定义需要在 overlay 元素上设置的 CSS 类列表,以空格分隔。参阅 Overlay。

pageSize

设置每个请求获取选项的最大数量,值必须大于 0。参阅 选项获取回调。

50

事件和处理器

通用事件和处理器 对所有组件都是一样的配置。 下面是 comboBox 的特殊事件和处理器:

在 Jmix Studio 生成处理器桩代码时,可以使用 Jmix UI 组件面板的 Handlers 标签页或者视图类顶部面板的 Generate Handler 添加,也可以通过 Code → Generate 菜单(Alt+Insert / Cmd+N)生成。

名称

描述

CustomValueSetEvent

com.vaadin.flow.component.combobox.ComboBoxBase.CustomValueSetEvent 当用户输入非空值,且不匹配任何已有选项时触发。如需启用自定义输入,请设置 allowCustomValue 属性为 true。

itemLabelGenerator

com.vaadin.flow.component.ItemLabelGenerator 可以自定义某个选项展示给用户的名称。参阅 自定义选项标签。

itemsFetchCallback

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

renderer

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

参考