comboBox 下拉列表
comboBox 支持用户从一组预定义的选项中选择单一值。
XML 元素 |
|
|---|---|
Java 类 |
|
基本用法
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 进行处理。
|
下面的示例中展示了如何为选项列表添加新的值,并在将来使用:
<comboBox id="comboBox"
label="Magic Box"
allowCustomValue="true"
helperText="Entered value will be added to the items"/>
@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 组件。
|
|
编程式获取选项
选项的获取也可以通过 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 注解实现。
<comboBox id="iconsComboBox"
label="Icons"
width="20em"/>
@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 元素 |
|
|---|---|
内部元素 |
custom - decimalMax - decimalMin - digits - doubleMax - doubleMin - email - max - min - negativeOrZero - negative - notBlank - notEmpty - notNull - positiveOrZero - positive - regexp - size |
样式版本
使用 themeNames 属性配置一个或多个样式。
| 样式 | 描述 | 支持的主题 |
|---|---|---|
|
组件较小 |
Aura, Lumo |
|
字段值左对齐 |
Aura, Lumo |
|
字段值居中 |
Aura, Lumo |
|
字段值右对齐 |
Aura, Lumo |
|
帮助文字显示在字段上方,标题下方。 |
Aura, Lumo |
XML 属性
下面是 comboBox 的特殊属性:
| 名称 | 描述 | 默认值 |
|---|---|---|
如果 |
|
|
当 |
|
|
控制该组件是否显示一个清除按钮。 |
|
|
|
— |
|
设置每个请求获取选项的最大数量,值必须大于 0。参阅 选项获取回调。 |
|
下面是 comboBox 支持的其他通用属性:
id - alignSelf - ariaLabel - ariaLabelledBy - autofocus - classNames - colspan - css - dataContainer - datatype - enabled - errorMessage - focusShortcut - height - helperText - label - maxHeight - maxWidth - minHeight - minWidth - pattern - placeholder - property - readOnly - required - requiredMessage - tabIndex - themeNames - title - visible - width
事件和处理器
下面是 comboBox 的特殊事件和处理器:
| 名称 | 描述 |
|---|---|
|
|
|
|
该处理器仅在需要时才获取数据。参考 编程式获取选项。 |
|
设置 |
|
验证组件值。 |
下面是 comboBox 支持的其他通用事件:
XML 内部元素
一个 comboBox 可以包含 itemsQuery、prefix、tooltip 和 validator 作为内部元素。