comboBox 下拉列表

comboBox 支持用户从一组预定义的选项中选择单一值。

XML 元素

comboBox

Java 类

JmixComboBox

基本用法

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

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

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

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

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

使用 comboBox 的最简单情况就是为实体属性选择一个枚举值。下面的示例中,组件用于编辑 Customer 实体的 grade 属性。

<data>
    <instance id="customerDc"
              class="io.jmix.uisamples.entity.Customer"
              fetchPlan="_local"/>
</data>
<layout>
    <comboBox dataContainer="customerDc" property="grade"/>
</layout>

customerDc 实例容器中带有编辑的额实体。dataContainer 和 property 将 comboBox 绑定至实体的 grade 属性。

自定义选项

从列表构建选项

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

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

<instance id="orderDc"
          class="io.jmix.uisamples.entity.Order"
          fetchPlan="_local"/>
<comboBox id="amountComboBox"
          label="Items List"
          dataContainer="orderDc"
          property="amount"/>

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

@ViewComponent
protected JmixComboBox<BigDecimal> amountComboBox;
    amountComboBox.setItems(getAmountItemsList());
protected List<BigDecimal> getAmountItemsList() {
    return List.of(
            BigDecimal.valueOf(1000),
            BigDecimal.valueOf(2000),
            BigDecimal.valueOf(3000),
            BigDecimal.valueOf(4000)
    );
}

组件的下拉列表中会显示 1000、2000、3000 和 4000。选择的值会设置到 orderDc 数据容器中实体的 amount 属性上。

自定义选项标签

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

@ViewComponent
protected JmixComboBox<Integer> ageComboBox;
    ComponentUtils.setItemsMap(ageComboBox, getAgeItemsMap());
protected Map<Integer, String> getAgeItemsMap() {
    LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
    map.put(20, "Twenty");
    map.put(30, "Thirty");
    map.put(40, "Forty");
    map.put(50, "Fifty");
    return map;
}

枚举选项

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

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

<comboBox id="gradeComboBox"
          label="Items Enum"
          dataContainer="customerDc"
          itemsEnum="io.jmix.uisamples.entity.CustomerGrade"
          property="grade"
          placeholder="Select grade"/>

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

@ViewComponent
private JmixComboBox<OnboardingStatus> enumComboBox;

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

自定义过滤

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

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

@ViewComponent
protected JmixComboBox<String> noFilterComboBox;
@ViewComponent
protected JmixComboBox<String> startsWithFilterComboBox;
@ViewComponent
protected JmixComboBox<String> containsFilterComboBox;

@Subscribe
protected void onInit(InitEvent event) {
    List<String> itemsList = List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");

    noFilterComboBox.setItems(itemsList);
    startsWithFilterComboBox.setItems(getStartsWithFilter(), itemsList);
    containsFilterComboBox.setItems(getContainsFilter(), itemsList);
}

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

protected ComboBox.ItemFilter<String> getContainsFilter() {
    return (dayOfWeek, filterString) -> dayOfWeek.toLowerCase().contains(filterString.toLowerCase());
}

自定义选项值

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

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

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

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

XML
<comboBox id="comboBox"
          label="Magic Box"
          allowCustomValue="true"
          helperText="Entered value will be added to the items"/>
Java
@ViewComponent
protected JmixComboBox<String> comboBox;

@Autowired
protected Notifications notifications;

protected List<String> items = Lists.newArrayList("One", "Two", "Tree");

@Subscribe
protected void onInit(InitEvent event) {
    comboBox.setItems(items);
}

@Subscribe("comboBox")
protected void onComboBoxCustomValueSet(ComboBoxBase.CustomValueSetEvent<ComboBox<String>> event) {
    String customValue = event.getDetail();
    items.add(customValue);

    comboBox.setItems(items);
    comboBox.setValue(customValue);

    notifications.show(customValue + " added");
}

选项获取回调

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

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

声明式获取选项

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

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

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

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

comboBox 中配置 itemsQuery 的示例:

<comboBox id="declarativeComboBox" label="Customer">
    <itemsQuery searchStringFormat="(?i)%${inputString}%"
                escapeValueForLike="true">
        <query>
            <![CDATA[select e.name from Customer e where e.name
            like :searchString escape '\' order by e.name asc]]>
        </query>
    </itemsQuery>
</comboBox>

组件的 pageSize 属性定义从数据库加载数据的每页大小。默认 50。

可以看到,comboBox 中的 itemsQuery 并不需要 class 和 fetchPlan 属性配置,因为查询语句是要返回量值的列表(注意结果集中的 e.name)。如果需要处理的是实体,请使用 entityComboBox 组件。

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

@Supply(to = "programmaticComboBox", subject = "renderer")
protected Renderer<Customer> comboBoxTextRenderer() {
    return new TextRenderer<>(Customer::getName);
}

@Install(to = "programmaticComboBox", subject = "itemsFetchCallback")
protected Stream<Customer> programmaticComboBoxItemsFetchCallback(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 获取。

自定义选项标签

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

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

选项渲染

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

XML
<comboBox id="iconsComboBox"
          label="Icons"
          width="20em"/>
Java
@ViewComponent
protected JmixComboBox<VaadinIcon> iconsComboBox;

@Autowired
protected UiComponents uiComponents;

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

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

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

        return contentBox;
    });
}

Overlay

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

使用 classNames 属性可以添加自定义的 CSS 类。可以用自定义的类对组件的遮罩层设置不同的样式。

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

在 css 文件中自定义样式:

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

验证

如需检查 comboBox 组件中的值,可以在内部的 validators XML 元素配置一个 验证器。

comboBox 支持下列预定义的验证器:

XML 元素

validators

内部元素

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

样式版本

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

样式 描述 支持的主题

small

组件较小

Aura, Lumo

align-left

字段值左对齐

Aura, Lumo

align-center

字段值居中

Aura, Lumo

align-right

字段值右对齐

Aura, Lumo

helper-above-field

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

Aura, Lumo

XML 属性

下面是 comboBox 的特殊属性:

名称 描述 默认值

allowCustomValue

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

false

autoOpen

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

true

clearButtonVisible

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

false

itemsEnum

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

—

pageSize

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

50

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

事件和处理器

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

名称 描述

CustomValueSetEvent

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

itemLabelGenerator

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

itemsFetchCallback

该处理器仅在需要时才获取数据。参考 编程式获取选项。

renderer

设置 Renderer,负责对 comboBox 的选项进行渲染。但是这个渲染器不会影响选中值的渲染效果 - 这个需要使用 ItemLabelGenerator。参考 选项渲染。

validator

验证组件值。

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

XML 内部元素

一个 comboBox 可以包含 itemsQuery、prefix、tooltip 和 validator 作为内部元素。

参考