multiSelectComboBox 多选下拉框
multiSelectComboBox 支持用户从下拉列表选择一项或多项。该组件与 comboBox 类似。
XML 元素 |
|
|---|---|
Java 类 |
|
基本用法
当用户点击控件时可以打开下拉列表。使用键盘的上下键或者在控件中输入内容也可以打开下拉列表。
<multiSelectComboBox id="multiSelectComboBox"/>
<multiSelectComboBox itemsEnum="io.jmix.uisamples.entity.Day" clearButtonVisible="true" width="17em"/>
@ViewComponent
protected JmixMultiSelectComboBox<String> multiSelectComboBox;
@Subscribe
protected void onInit(InitEvent event) {
multiSelectComboBox.setItems("CSS", "HTML", "Java", "JavaScript", "JSON", "Kotlin", "XML");
multiSelectComboBox.select("Java", "Kotlin");
}
数据感知的 multiSelectComboBox
multiSelectComboBox 专为存储多个值的属性而设计。当该组件绑定实体属性时,属性类型应为集合,例如 List 或 Set。
最常见的用例是为多对多关联选择相关实体:
@JmixEntity
@Table(name = "HOBBY")
@Entity
public class Hobby {
/* attributes */
}
@JmixEntity
@Entity
@Table(name = "USER_")
public class User {
/* other attributes */
@JoinTable(name = "USER_HOBBY_LINK",
joinColumns = @JoinColumn(name = "USER_ID"),
inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
@ManyToMany
private List<Hobby> userHobbies;
}
此时,multiSelectComboBox 支持用户选择多个 Hobby 实例,并且该对应关系存储在连接表中。
如需创建数据感知的 multiSelectComboBox,请使用 dataContainer 和 property 属性将组件绑定到集合属性。使用 itemsContainer 属性提供可用项列表。以下示例生成一个数据感知的 multiSelectComboBox。
<data>
<instance id="productDc"
class="io.jmix.uisamples.entity.Product"
fetchPlan="_local">
</instance>
<collection id="productTagsDc"
class="io.jmix.uisamples.entity.ProductTag"
fetchPlan="_local">
<loader id="productTagsDl">
<query>
<![CDATA[select e from ProductTag e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<layout>
<multiSelectComboBox id="multiSelectComboBox" width="15em" label="Product tags"
dataContainer="productDc" property="tags"
itemsContainer="productTagsDc"/>
<hbox>
<span text="Value in the container:"/>
<span id="spanValue"/>
</hbox>
</layout>
@ViewComponent
protected InstanceContainer<Product> productDc;
@ViewComponent
protected Span spanValue;
@Autowired
protected Metadata metadata;
@Subscribe
protected void onInit(InitEvent event) {
Product product = metadata.create(Product.class);
productDc.setItem(product);
}
@Subscribe("multiSelectComboBox")
protected void onMultiSelectComboBoxFieldValueChange(
TypedValueChangeEvent<JmixMultiSelectComboBox<Product>, Product> changeEvent) {
spanValue.setText(getSelectedTagsInstanceName());
}
protected String getSelectedTagsInstanceName() {
return productDc.getItem().getTags()
.stream()
.map(ProductTag::getInstanceName)
.collect(Collectors.joining(", "));
}
|
|
组件的值包含所选的条目。当组件绑定集合属性时,Jmix 会将选定的条目转换为属性集合类型,例如 List 或 Set。
使用 MetaClass
使用 multiSelectComboBox 时,还可以不直接指定关联的数据,即无需设置 dataContainer 或 property 属性。此时,需要使用 metaClass 属性指定实体类型。itemsContainer 属性指定选项实例的集合。
例如,组件可以使用 Hobby 实体,其元数据类为 Hobby。
<multiSelectComboBox metaClass="Hobby"
itemsContainer="userHobbiesDc"/>
自定义选项标签
通过 itemLabelGenerator 控制如何显示选项的文本:
<data>
<collection id="productTagsDc"
class="io.jmix.uisamples.entity.ProductTag"
fetchPlan="_local">
<loader id="productTagsDl">
<query>
<![CDATA[select e from ProductTag e]]>
</query>
</loader>
</collection>
</data>
<multiSelectComboBox id="multiSelectComboBox" label="Product tags" itemsContainer="productTagsDc"/>
@Install(to = "multiSelectComboBox", subject = "itemLabelGenerator")
protected String multiSelectComboBoxItemLabelGenerator(ProductTag productTag) {
return "#" + productTag.getName();
}
自定义选项渲染器
还可以为每个选项提供一个组件以显示更丰富的内容。下面的示例中使用图标和名称显示每个枚举值:
<multiSelectComboBox id="iconsMultiSelectComboBox" clearButtonVisible="true"
label="Icons"
width="20em"/>
@ViewComponent
protected JmixMultiSelectComboBox<VaadinIcon> iconsMultiSelectComboBox;
@Autowired
protected UiComponents uiComponents;
@Subscribe
protected void onInit(InitEvent event) {
iconsMultiSelectComboBox.setItems(VaadinIcon.values());
}
@Supply(to = "iconsMultiSelectComboBox", subject = "renderer")
protected Renderer<VaadinIcon> multiSelectComboBoxComponentRenderer() {
return new ComponentRenderer<>(vaadinIcon -> {
HorizontalLayout contentBox = uiComponents.create(HorizontalLayout.class);
contentBox.setPadding(false);
contentBox.add(vaadinIcon.create());
contentBox.add(vaadinIcon.name());
return contentBox;
});
}
自动展开
multiSelectComboBox 可以自动扩展其宽度以容纳表示所选条目的小卡片。仅当所需的扩展方向未定义尺寸时才有效(例如,设置 max-width 会限制组件的宽度,从而无法扩展)。支持的选项:
-
VERTICAL- 组件垂直扩展,小卡片会自动换行。 -
HORIZONTAL- 组件水平扩展直至max-width的宽度,然后会折叠溢出的卡片。 -
BOTH- 组件首先水平扩展直至max-width的宽度,然后垂直扩展,小卡片会自动换行。 -
NONE- 组件不会扩展,并折叠溢出的卡片。== 已选条目置顶
selectedItemsOnTop 属性控制所选条目在选项列表 overlay 中的显示方式。
以下是其工作原理:
-
如果
selectedItemsOnTop设置为true,则已选择的条目将显示在 overlay 的顶部,其他未选择的条目将保留在底部。这种排列方式为用户提供了非常直观的展示,特别是用户需要频繁查看最近选择的条目时。 -
如果
selectedItemsOnTop设置为false(默认值),则所选条目将按其选择顺序显示,而不会移动到 overlay 的顶部。这种排列保持了选择的顺序,当选择的顺序比较重要或与其他 UI 元素的视觉一致性很重要的情况下,可以首选这种排列方式。
选项获取回调
multiSelectComboBox 可以根据用户输入批量加载选项。
例如,当用户输入 foo 时,组件会从数据库中加载最多 50 个名称中包含 foo 的选项,并在下拉列表显示。当用户向下滚动列表时,组件会获取具有相同查询语句的下一批 50 个选项,并将添加到选项列表中。
声明式获取选项
要实现这个功能,需要定义内部的 itemsQuery 元素。
itemsQuery 元素需要在内部的 query 元素中定义 JPQL 查询语句,以及通过几个属性配置如何加载数据:
-
escapeValueForLike- 启用搜索包含特殊符号的值:%、\等。默认为false。 -
searchStringFormat- 一个包含变量占位符的字符串,该占位符在查询时将替换为实际值。 -
class(可选)- 指定需要获取实体类的全限定名称。 -
fetchPlan(可选)- 指定加载数据时需要使用的 fetch plan。
itemsQuery 元素有下列内部元素:
-
query- 定义 JPQL 查询语句的元素。 -
fetchPlan- 可选的描述符,用于定义 fetch plan。
multiSelectComboBox 中配置 itemsQuery 的示例:
<multiSelectComboBox id="declarativeMultiSelectComboBox" label="Customer"
metaClass="Customer">
<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>
</multiSelectComboBox>
|
|
编程式获取选项
选项的获取也可以通过 itemsFetchCallback 处理器编程式定义。示例:
@Autowired
protected DataManager dataManager;
protected Collection<Customer> customers;
@Subscribe
protected void onInit(InitEvent event) {
customers = dataManager.load(Customer.class).all().list();
}
@Install(to = "programmaticMultiSelectComboBox", subject = "itemsFetchCallback")
protected Stream<Customer> programmaticMultiSelectComboBoxItemsFetchCallback(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 获取。
样式版本
使用 themeNames 属性配置一个或多个样式。
| 样式 | 描述 | 支持的主题 |
|---|---|---|
|
组件尺寸较小 |
Aura, Lumo |
|
字段值左对齐 |
Aura, Lumo |
|
字段值居中 |
Aura, Lumo |
|
字段值右对齐 |
Aura, Lumo |
|
帮助文字显示在字段上方,标题下方。 |
Aura, Lumo |
XML 属性
下面是 multiSelectComboBox 的特殊属性:
| 名称 | 描述 | 默认值 |
|---|---|---|
用户是否可以输入选项中没有的值。 |
— |
|
当组件没有足够的空间展示选项的小卡片时,使用这个属性控制组件的行为。参阅 自动展开。 |
|
|
当组件获得焦点时,是否自动展开。 |
— |
|
组件是否显示一个清除按钮。 |
|
|
设置选项的数据容器。 |
— |
|
设置选项的枚举。 |
— |
|
为组件设置一个实体类。如果组件不关联数据容器的话,需要设置改属性。参考 使用 MetaClass。 |
— |
|
设置下拉列表是否展开。 |
|
|
设置每页的数量。 |
— |
|
是否在 overlay 顶部显示已选条目的分组。参阅 已选条目置顶。 |
|
下面是 multiSelectComboBox 支持的其他通用属性:
id - alignSelf - allowedCharPattern - ariaLabel - ariaLabelledBy - autofocus - classNames - colspan - css - dataContainer - enabled - errorMessage - focusShortcut - height - helperText - label - maxHeight - maxWidth - minHeight - minWidth - placeholder - property - readOnly - required - requiredMessage - tabIndex - themeNames - title - visible - width
事件和处理器
下面是 multiSelectComboBox 的特殊事件和处理器:
| 名称 | 描述 |
|---|---|
当用户输入自定义内容时触发。 |
|
|
|
仅在需要时加载选项数据。参阅 选项获取回调。 |
|
用于设置 |
|
验证组件值。 |
下面是 multiSelectComboBox 支持的其他通用事件:
XML 内部元素
一个 multiSelectComboBox 可以包含 fragmentRenderer、itemsQuery、tooltip 和 validator 作为其内部元素。