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);
}

组件的下拉列表中会显示 12345。选择的值会设置到 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 不需要定义 classfetchPlan 属性,因为查询语句需要返回标量值的一个列表(注意这里使用了 e.name)。如需处理实体,请使用 entityComboBox 组件。

编程式配置

选项的获取也可以通过 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 属性可以调整文本对齐、帮助文本显示位置或组件的尺寸。

对齐方式

支持三种对齐方式:align-left(默认)、align-rightalign-center

combo box alignment
XML 代码
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          themeNames="align-left"
          helperText="The align-left alignment"/>
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          themeNames="align-center"
          helperText="The align-center alignment"/>
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          themeNames="align-right"
          helperText="The align-right alignment"/>

帮助文本显示位置

设置 helper-above-field 会将帮助文字显示在控件上方而不是默认的下方:

combo box helper above field
XML 代码
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          label="Onboarding status"
          helperText="Helper text with helper-above-field"
          themeNames="helper-above-field"/>
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          label="Onboarding status"
          helperText="Helper text without helper-above-field"/>

尺寸

支持两种尺寸:默认大小或 small

combo box size
XML 代码
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          helperText="Default size"/>
<comboBox itemsEnum="com.company.onboarding.entity.OnboardingStatus"
          themeNames="small"
          helperText="Small size"/>

验证

如需检查 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 属性

在 Jmix 中,所有组件都有一些作用一致的 通用属性。 下面是 comboBox 的特殊属性:

名称

描述

默认值

allowCustomValue

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

false

autoOpen

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

true

itemsEnum

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

overlayClass

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

pageSize

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

50

事件和处理器

在 Jmix 中,所有组件都有一些 通用事件和处理器,可以按相同的方法设置。 下面是 comboBox 的特殊事件和处理器:

在 Jmix Studio 生成处理器桩代码时,可以使用 Jmix UI 组件面板的 Handlers 标签页或者视图类顶部面板的 Generate Handler 添加,也可以通过 CodeGenerate 菜单(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

参考