EntitySuggestionField 实体提示选择

EntitySuggestionField - 实体提示控件 用于根据用户输入的字符串搜索实体实例。当用户点击右侧的按钮时,执行对应的操作。

EntitySuggestionField 是一个输入控件,当用户输入几个字符时,如果能匹配上一些选项,则会展示匹配选项的下拉列表。EntitySuggestionField 在输入每个符号之后刷新选项列表。

选项列表根据应用程序开发者定义的逻辑在后台服务端加载。

事实上,EntitySuggestionField 是 SuggestionField 和 EntityPicker 的组合。

组件的 XML 名称:entitySuggestionField。

基本用法

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

  • 用户需要选择单一实体实例。

  • 建议值列表的长度对于使用 EntityComboBox 来说太长了。

  • 希望在数据库完成高效搜索,而不是在 UI 层加载太多数据。

entity suggestion field

创建数据感知的 EntitySuggestionField,可以使用 dataContainer 和 property XML 属性以及 query 元素:

<data>
    <instance id="addressDc" class="ui.ex1.entity.Address"> (1)
        <fetchPlan extends="_base"> (2)
            <property name="country" fetchPlan="_instance_name"/>
            <property name="city" fetchPlan="_base">
                <property name="country" fetchPlan="_base"/>
            </property>
        </fetchPlan>
    </instance>
</data>
<layout>
    <vbox spacing="true">
        <entitySuggestionField id="countryField"
                               inputPrompt="msg://entitySuggestionField/select"
                               caption="msg://ui.ex1.entity/Address.country"
                               dataContainer="addressDc"
                               property="country">
            <query entityClass="ui.ex1.entity.Country"
                   searchStringFormat="%${searchString}%"
                   escapeValueForLike="true"
                   fetchPlan="_instance_name">
                <![CDATA[select c from uiex1_Country c where lower(c.name)
                like lower(:searchString) escape '\']]>
            </query>
        </entitySuggestionField>
    </vbox>
</layout>
1 InstanceContainer - Address 实体。
2 数据容器内实体的 fetch plan。

界面为具有 country 属性的 Address 实体定义了 id 为 addressDc 的数据容器。在 entitySuggestionField 元素中,通过 dataContainer 属性连接到 addressDc 数据容器,并给 property 属性设置了 country 实体属性。实体属性应该引用另一个实体,在上面的示例中就是 Country 实体。

选项定义

选项列表可以在 XML 描述中用 query 元素定义,或者在控制器中用 SearchExecutor 接口编程式的定义。

query 元素

query 是一个可选的 XML 元素,支持定义查询语句搜索建议值。

query 元素有下列属性:

  • entityClass(必需)- 实体的全限定名称。

  • fetchPlan - 可选属性,指定加载实体所需的 fetch plan。

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

  • searchStringFormat - Groovy 字符串;可以使用任何有效的 Groovy 表达式。

如需在 Jmix Studio 中添加 query,可以在界面 XML 或者 Component Hierarchy 面板中选择组件,然后点击 Component Inspector 面板的 Add→Query 按钮。

SearchExecutor

如果未定义 query,则需要用 SearchExecutor 编程式设置选项列表。

SearchExecutor 是功能接口,包含单一方法:List<E> search(String searchString, Map<String, Object> searchParams)。

searchString 参数是用户输入的字符串,可用于过滤选项。

首先,在 XML 中声明一个组件:

<entitySuggestionField id="entityField"
                       dataContainer="addressDc"
                       property="country"
                       caption="Country"/>

然后为组件设置 SearchExecutor:

@Autowired
private DataManager dataManager;

@Install(to = "entityField", subject = "searchExecutor")
private List entityFieldSearchExecutor(String searchString,
                                       Map<String, Object> searchParams) {
    return dataManager.load(Country.class)
            .query("e.name like ?1 order by e.name", "(?i)%" + searchString + "%")
            .list();
}

可以用 Studio 生成 SearchExecutor 实现的桩代码。

search() 方法在后台线程中执行,因此它无法访问可视化组件或数据容器。可直接调用 DataManager 或中间件服务;或处理并返回预先加载到界面的数据。

也可以使用 escapeForLike() 方法来搜索包含特殊符号的值:

@Autowired
private DataManager dataManager;

@Install(to = "entitySuggestionField", subject = "searchExecutor")
private List<Customer> entitySuggestionFieldSearchExecutor(String searchString,
                                                           Map<String, Object> searchParams) {
    searchString = QueryUtils.escapeForLike(searchString);
    return dataManager.load(Customer.class)
            .query("e.firstName like ?1 escape '\\' order by e.firstName", "(?i)%"
                    + searchString + "%")
            .list();
}

metaClass

也可以在不绑定数据容器的情况下使用 EntitySuggestionField,比如,没有设置 dataContainer 和 property。此时,需要设置 MetaClass 指定实体类型,示例:

<entitySuggestionField id="metaClassField"
                       metaClass="uiex1_Country"
                       caption="Country"/>

搜索逻辑通过 SearchExecutor 定义:

@Autowired
private DataManager dataManager;

@Install(to = "metaClassField", subject = "searchExecutor")
private List<Country> metaClassFieldSearchExecutor(String searchString,
                                                   Map<String, Object> searchParams) {
    return dataManager.load(Country.class)
            .query("e.name like ?1 order by e.name", "(?i)%" + searchString + "%")
            .list();
}

操作

可以给 EntitySuggestionField 设置自定义或预定义的操作,操作作为按钮显示在右侧。 定义操作可以用 XML 中用内部的 actions 元素或者在控制器中用 addAction() 方法编程式添加。

如需在 Jmix Studio 中添加 action,可以在界面 XML 或者 Component Hierarchy 面板中选择组件,然后点击 Component Inspector 面板的 Add→Action 按钮。

预定义操作

如果创建无操作的 EntitySuggestionField,XML 加载器仅定义 entity_lookup 和 entity_open 操作。还有 entity_clear 和 entity_openComposition 操作。

如需添加其他预定义操作,例如,entity_clear,可以按照下面这样指定 actions 元素:

<entitySuggestionField dataContainer="addressDc"
                       property="country"
                       caption="Country">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="open" type="entity_open"/>
        <action id="clear" type="entity_clear"/>
    </actions>
</entitySuggestionField>

actions 元素不会扩展但会覆盖一组标准操作。应该明确定义所有必需操作的标识符。

使用 addAction() 以编程方式设置标准操作。如果在组件的 XML 描述中没有内部的 actions 元素,就可以使用这个方法添加缺少的标准操作:

@Autowired
private EntitySuggestionField<Country> entitySuggestionField;

@Autowired
private Actions actions;

@Subscribe
public void onInit(InitEvent event) {
    entitySuggestionField.addAction(actions.create(EntityClearAction.class));
}

自定义操作

EntitySuggestionField 的自定义操作与 EntityPicker 的 自定义操作 类似。

事件和处理器

如需使用 Jmix Studio 生成处理器的桩代码,需要在界面 XML 描述或者 Jmix UI 层级结构面板选中该组件,然后用 Jmix UI 组件面板的 Handlers 标签页生成。

或者可以使用界面控制器顶部面板的 Generate Handler 按钮。

ArrowDownHandler

ArrowDownEvent 当建议值弹窗隐藏且用户按下 向下箭头 时发送。

可以设置自定义的处理方法并使用 EntitySuggestionField.showSuggestions(),该方法接收一组实体作为建议值展示:

@Autowired
private CollectionContainer<Country> countriesDc;

@Autowired
private EntitySuggestionField<Country> countryField;

@Install(to = "countryField", subject = "arrowDownHandler")
private void countryFieldArrowDownHandler(SuggestionFieldComponent.ArrowDownEvent
                                                      arrowDownEvent) {
    countryField.showSuggestions(new ArrayList<>(countriesDc.getItems()));
}

ContextHelpIconClickHandler

EnterPressHandler

参阅 ComboBox 处理用户输入 部分编程式注册的示例。

EnterPressHandler 也可以在界面控制器中使用 @Install 注解声明式的定义。参阅 EntityComboBox 处理用户输入 部分的示例。

FieldIconProvider

参阅 FieldIconProvider。

FieldValueChangeEvent

Formatter

为组件添加一个 formatter。

下面的例子中,我们展示 cityFieldFormat 实体建议控件 formatter 的用法:

@Install(to = "cityFieldFormat", subject = "formatter")
protected String cityFieldFormatFormatter(City value) {
    return value != null
            ? value.getName() + " (" + (value.getCountry() != null
            ? value.getCountry().getName() : "not defined") + ")"
            : null;
}

如需以编程的方式添加 formatter,使用组件的 addFormatter() 方法。

OptionCaptionProvider

SearchExecutor

参阅 SearchExecutor。

Validator

参阅 Validator。

ValueChangeEvent

参阅 ValueChangeEvent。

EntitySuggestionField XML 元素