Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Items fetch callback #1923

Closed
glebfox opened this issue Jun 23, 2023 · 4 comments
Closed

Support Items fetch callback #1923

glebfox opened this issue Jun 23, 2023 · 4 comments
Assignees
Milestone

Comments

@glebfox
Copy link
Contributor

glebfox commented Jun 23, 2023

Consider implementing com.vaadin.flow.data.provider.CallbackDataProvider instead of separate component

Solution

The setItemsFetchCallback method is added for the following components:

  • ComboBox
  • EntityComboBox
  • MultiselectComboBox
  • MultiselectComboBoxPicker

XML

All components support an optional itemsQuery element that enables defining a query for selecting suggested values.

The itemsQuery element for the EntityComboBox has the following attributes:

  • class (required) - a full qualified name of an entity class.
  • fetchPlan - an optional attribute that specifies the fetch plan to be used for loading the queried entity.
  • escapeValueForLike - enables searching for the values that contain special symbols: %, \, etc. The default value is false.
  • searchStringFormat - a string that contains a variable to be substituted with actual value by io.jmix.flowui.sys.substitutor.StringSubstitutor. The default implementation delegates its work to org.apache.commons.text.StringSubstitutor.

The itemsQuery element for the EntityComboBox has the following nested elements:

  • query - an element that contains a JPQL query
  • fetchPlan - an optional descriptor of inline fetch plan
<entityComboBox id="assigneeField" metaClass="User" width="25em">
    <actions>
        <action id="entityLookup" type="entity_lookup"/>
        <action id="entityClear" type="entity_clear"/>
    </actions>
    <itemsQuery class="com.company.demo.entity.User"
                searchStringFormat="(?i)%${inputString}%"
                escapeValueForLike="true">
        <fetchPlan extends="_instance_name"/>
        <query>
            <![CDATA[select e from User e where e.username like :searchString escape '\' order by e.username asc]]>
        </query>
    </itemsQuery>
</entityComboBox>

The itemsQuery element for the ComboBox has the following attributes:

  • escapeValueForLike - enables searching for the values that contain special symbols: %, \, etc. The default value is false.
  • searchStringFormat - a string that contains a variable to be substituted with actual value by io.jmix.flowui.sys.substitutor.StringSubstitutor. The default implementation delegates its work to org.apache.commons.text.StringSubstitutor.

The itemsQuery element for the EntityComboBox has the following nested element:

  • query - an element that contains a JPQL query

Note: there is no entityClass and fetchPlan because ComboBox assumes that scalar values will be loaded. In case if entities use EntityComboBox.

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

The itemsQuery element for the MultiSelectComboBox and MultiSelectComboBoxPicker has the following attributes:

  • class (optional) - a full qualified name of an entity class.
  • fetchPlan - an optional attribute that specifies the fetch plan to be used for loading the queried entity.
  • escapeValueForLike - enables searching for the values that contain special symbols: %, \, etc. The default value is false.
  • searchStringFormat - a string that contains a variable to be substituted with actual value by io.jmix.flowui.sys.substitutor.StringSubstitutor. The default implementation delegates its work to org.apache.commons.text.StringSubstitutor.

The itemsQuery element for the MultiSelectComboBox and MultiSelectComboBoxPicker has the following nested elements:

  • query - an element that contains a JPQL query
  • fetchPlan - an optional descriptor of inline fetch plan
<multiSelectComboBox id="tagsField" property="tags">
    <itemsQuery class="com.company.demo.entity.Tag"
                searchStringFormat="(?i)%${inputString}%"
                escapeValueForLike="true">
        <fetchPlan extends="_instance_name"/>
        <query>
            <![CDATA[select e from Tag e where e.name like :searchString escape '\' order by e.name asc]]>
        </query>
    </itemsQuery>
</multiSelectComboBox>

Note: Because both MultiSelectComboBox and MultiSelectComboBoxPicker work with entities and scalar values itemsQuery has class attribute but its optional.

View Controller

If itemsQuery is not defined, you should programmatically set the list of options using setItemsFetchCallback.

<entityComboBox id="assigneeField" property="assignee">
    <actions>
        <action id="entityLookup" type="entity_lookup"/>
        <action id="entityClear" type="entity_clear"/>
    </actions>
</entityComboBox>
@Install(to = "assigneeField", subject = "itemsFetchCallback")
private Stream<User> assigneeFieldItemsFetchCallback(final Query<User, String> query) {
    return usersDc.getItems().stream().skip(query.getOffset()).limit(query.getLimit());
}

Note: Because the real work is delegated to com.vaadin.flow.data.provider.HasLazyDataView#setItems(com.vaadin.flow.data.provider.CallbackDataProvider.FetchCallback<T,F>), the QueryTrace instance is passed to the fetch callback. As a result, there are several limitations:

  • query.getOffset() and query.getLimit() methods must be called, otherwise an exception is thrown.
  • The amount of items returned from callback cannot exceed the limit value, otherwise an exception is thrown.
@glebfox glebfox added in: flowui candidate Possible candidate for future releases labels Jun 23, 2023
@Flaurite
Copy link
Contributor

Flaurite commented Jun 30, 2023

I've tried implement suggestions for JmixMultiSelectComboBox using CallbackDataProvider.FetchCallback similar to io.jmix.ui.component.TagField:

protected Stream<UserDetails> onFieldFetchCallback(Query<UserDetails, String> query) {
    int offset = query.getOffset(); // ignore value
    int limit = query.getLimit(); // ignore value

    String enteredValue = query.getFilter().orElse(null);

    return StringUtils.isNotBlank(enteredValue)
            ? (Stream<UserDetails>) userRepository.getByUsernameLike(enteredValue).stream()
            : Stream.empty();
}

But there is a problem with value conversion in JmixMultiSelectComboBox#onValueChange(). Loaded options are empty due to calling fetch with empty Query. So value conversion produces empty values.

@glebfox glebfox removed the candidate Possible candidate for future releases label Jul 3, 2023
@glebfox glebfox self-assigned this Jul 5, 2023
@glebfox glebfox added the size: M label Jul 5, 2023
@knstvk knstvk added this to October 2023 release 2.1 in Jmix Roadmap Jul 5, 2023
@knstvk knstvk changed the title Implement SuggestionField SuggestionField Jul 12, 2023
@knstvk knstvk changed the title SuggestionField SuggestionField component Jul 12, 2023
@glebfox glebfox changed the title SuggestionField component XML support for CallbackDataProvider Jul 20, 2023
@glebfox glebfox changed the title XML support for CallbackDataProvider Support Items fetch callback Jul 21, 2023
glebfox added a commit that referenced this issue Jul 28, 2023
@rusiaikinat rusiaikinat self-assigned this Aug 1, 2023
@knstvk
Copy link
Contributor

knstvk commented Oct 13, 2023

Needs some improvements:

  1. The variable inside searchStringFormat should be named inputString
  2. Ability to specify inline fetchPlan in nested fetchPlan element. Or maybe add also nested query element as in data loaders?

@knstvk knstvk reopened this Oct 13, 2023
@knstvk
Copy link
Contributor

knstvk commented Oct 13, 2023

@MaxKatyshev
Copy link

Jmix version: 2.1.999-SNAPSHOT
Jmix Studio plugin version: 2.1.SNAPSHOT5666-232
IntelliJ version: IntelliJ IDEA 2023.2.3 (Ultimate Edition)

verified

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

No branches or pull requests

6 participants