Filter

Компонент Filter – универсальное средство фильтрации данных.

Компонент позволяет производить быструю фильтрацию данных по произвольному набору условий, а также создавать фильтры для многократного использования.

XML-имя компонента: filter.

Основы

Filter должен быть связан с загрузчиком данных независимого CollectionContainer или KeyValueCollectionContainer. Он генерирует объект Condition, который устанавливается в загрузчик и затем обрабатывается хранилищем данных. Для JPA-сущности хранилище данных изменяет результирующий запрос JPQL. Таким образом, фильтрация осуществляется на уровне БД, и в память приложения загружаются только отобранные данные.

По умолчанию Jmix Studio генерирует Filter при создании для сущности экранов браузера и master-detail.

Ниже представлен пример декларации filter в XML-дескрипторе экрана:

<data>
    <collection id="customersDc" class="ui.ex1.entity.Customer">
        <fetchPlan extends="_base">
            <property fetchPlan="_base" name="city"/>
            <property name="favouriteBrands" fetchPlan="_base"/>
        </fetchPlan>
        <loader id="customersDl">
            <query>
                <![CDATA[select e from uiex1_Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<layout spacing="true" expand="customersTable">
    <filter dataLoader="customersDl" caption="Simple filter">
        <properties include=".*"/>
    </filter>
    <table id="customersTable"
           width="100%"
           dataContainer="customersDc">
        <columns>
            <column id="level"/>
            <column id="age"/>
            <column id="hobby"/>
            <column id="firstName"/>
            <column id="lastName"/>
            <column id="city"/>
            <column id="rewardPoints"/>
        </columns>
    </table>
</layout>

Здесь контейнер данных содержит коллекцию экземпляров сущности Customer. Загрузчик загружает коллекцию, используя JPQL-запрос. Компонент filter соединен с загрузчиком с помощью атрибута dataLoader. Данные отображаются компонентом Table, связанным с контейнером.

Типичный фильтр выглядит следующим образом:

filter anatomy
  • Выпадающее меню с сохраненными фильтрами и конфигурациями (2).

  • Кнопка Refresh с выпадающим меню. (3).

  • Выбор оператора (4).

  • Поле со значением условия (5).

  • Кнопка настроек фильтра (6).

По умолчанию компонент находится в режиме быстрой фильтрации. Это означает, что пользователь может добавить набор условий для разового поиска данных. После закрытия экрана условия будут удалены.

Пример быстрого фильтра

Представим, что у нас есть сущность Customer, и мы хотим:

  • Создать быстрый фильтр с несколькими условиями в экране Customer browser.

  • Сохранить этот фильтр на будущее.

Создание быстрого фильтра

  • Нажмите на ссылку Add search condition (1).

  • Выберите атрибут Age в списке Properties.

  • Выберите атрибут Hobby.

    Выбранные условия отображаются в верхней части панели фильтра.

  • Измените оператор и значение условия:

filter sample

Сохранение фильтра

  • Нажмите на кнопку настроек фильтра(6) и выберите Save with values.

  • Задайте имя нового фильтра в диалоговом окне Save filter configuration:

    filter sample save

Фильтр будет сохранен в выпадающем меню кнопки Refresh(3).

filter sample refresh

Пункт меню Reset filter позволяет сбросить все текущие условия поиска.

Добавление условий

Для того чтобы создать быстрый фильтр, нажмите на ссылку Add search condition (1). Отобразится экран выбора условий:

filter add condition

Рассмотрим возможные типы условий:

  • Properties – атрибуты данной сущности и связанных с ней сущностей. Отображаются только персистентные и динамические атрибуты, соответствующие правилам, указанным в элементе properties.

  • Predefined conditions – условия, заданные разработчиком в элементе conditions XML-дескриптора. Предопределенные условия изначально не добавлены ни в какие фильтры, но пользователь может выбрать их на экране Add Condition и добавить в конфигурацию во время выполнения.

  • Configurations могут быть созданы во время разработки или во время выполнения (в редакторе конфигураций).

Выбранные условия отображаются в верхней части панели фильтра. Рядом с каждым условием находится кнопка filter remove condition, позволяющая удалить их из набора.

Действия выпадающего списка кнопки Create соответствуют зарегистрированным компонентам фильтра. По умолчанию доступны три компонента фильтра – PropertyFilter, JpqlFilter, и GroupFilter:

filter create filter button

При наличии в проекте дополнения Search становится доступным новое full-text условие.

Таким образом, у пользователя есть возможность создавать условия фильтрации во время выполнения.

Условия по атрибутам

Property conditions editor позволяет пользователям настраивать атрибуты компонента PropertyFilter. PropertyFilter связан с атрибутом сущности.

filter property conditions

Выберите атрибут сущности в поле Property.

Поле Operation поле позволяет выбрать оператор условия. Список доступных операций зависит от типа атрибута.

Используйте атрибут Parameter name, чтобы задать имя параметра запроса. Это имя можно использовать для введения зависимостей между компонентами фильтра в конфигурации. Если значение не задано, то имя параметра генерируется случайным образом.

В поле Caption можно задать собственное название условия фильтрации по атрибутам.

Флажок Operation editable используется, чтобы задать видимость выбора оператора. Если этот флажок установлен, поле операции позволит выбрать оператор условия во время выполнения.

Флажок Operation caption visible используется, чтобы задать видимость названия операции.

В поле Default value для условия можно установить значение по умолчанию.

JPQL-условия

JPQL conditions editor позволяет пользователям создавать условия на основе выражений JPQL.

filter jpql conditions

В поле Parameter type нужно указать класс Java параметра условия. Значение No parameter позволяет создать условие без параметров. Например:

filter jpql conditions no parameters

Поле Caption обязательно для заполнения. В нем необходимо задать имя условия, отображаемое в фильтре.

Атрибут Parameter name используется для задания имени связанного параметра запроса. Это имя можно использовать для введения зависимостей между компонентами фильтра в конфигурации. Если значение не задано, то имя параметра генерируется случайным образом.

Флажок Has IN expression используется, чтобы определить, должно ли выражение JPQL содержать выражение IN. В этом случае приложение будет использовать компонент ValuesPicker для создания списка значений условия.

В поле Default value для условия можно установить значение по умолчанию.

В поле Join можно указать выражение JPQL, которое будет добавлено в секцию from запроса контейнера данных. Это может потребоваться для создания сложного условия по атрибуту связанной коллекции. Выражение должно начинаться с предложений join или left join. Вместо алиаса отбираемой сущности в выражении следует использовать плейсхолдер {E}.

filter jpql conditions join

Значение в поле Where задает выражение JPQL, которое будет добавлено в секцию where запроса контейнера данных. Вместо алиаса отбираемой сущности в выражении следует использовать плейсхолдер {E}. Параметр условия может быть только один, и если он определен в поле Parameter type, обозначается символом ?. Кроме вводимых пользователем параметров, можно использовать любое количество параметров атрибутов сессии и пользователя, например:

{E}.code = ? and {E}.area = :session_area

Группирующие условия

Group conditions editor позволяет пользователям объединять несколько условий в логическую группу.

filter group conditions

Выпадающий список Operation позволяет пользователям выбрать оператора логической группы.

Поле Caption обязательно для заполнения. В нем необходимо задать имя условия, отображаемое в фильтре.

Флажок Operation caption visible используется, чтобы задать видимость имени операции.

Чтобы добавить условие, нажмите кнопку Add. Появится экран Add condition.

Условия фильтрации содержатся в дереве. Пользователи могут определять порядок условий фильтрации в фильтре с помощью кнопок filter group conditions move down/filter group conditions move up и удалять и редактировать условия с помощью кнопок Remove и Edit.

Конфигурация

Конфигурация – это набор компонентов фильтра.

LogicalFilterComponent является корневым элементом конфигурации.

Конфигурация не содержит ссылок на все компоненты, а только ссылку на корневой элемент, из которого могут быть получены остальные компоненты фильтра.

Конфигурации могут быть созданы во время разработки или во время выполнения (с помощью экрана Configuration editor).

Конфигурация времени разработки

Конфигурация, созданная во время разработки, не может быть изменена и сохранена во время выполнения. Тем не менее, пользователь может использовать действие Copy, которое копирует все условия из конфигурации времени разработки в конфигурацию времени выполнения.

Все конфигурации, созданные во время разработки, отображаются в выпадающем меню(2) сохраненных фильтров и конфигураций:

filter design time configuration

Ниже приведен пример filter в XML-дескрипторе экрана с конфигурациями времени разработки:

<filter dataLoader="customersDl"
        id="filterDesignTime"
        caption="Filter with design-time configurations">
    <properties include=".*"/>
    <configurations>
        <configuration id="configuration_age_hobby" operation="AND"
                       name="Age AND Hobby Configuration" default="true">
            <propertyFilter property="age" operation="GREATER"/>
            <propertyFilter property="hobby" operation="IN_LIST"/>
        </configuration>
        <configuration id="configuration_level_rewards_points" operation="OR"
                       name="Level OR Rewards Points Configuration">
            <propertyFilter property="level" operation="EQUAL"/>
            <propertyFilter property="rewardPoints" operation="LESS_OR_EQUAL"/>
        </configuration>
    </configurations>
</filter>

id является обязательным атрибутом и должен быть уникальным в пределах данного фильтра. Если атрибут name не указан, то в качестве ключа в пакете сообщений используется id.

Используйте XML-атрибут default, чтобы установить конфигурацию, созданную во время разработки в качестве параметра фильтра по умолчанию. Таким образом, он появляется сразу после открытия экрана.

Конфигурация времени выполнения

Чтобы создавать, редактировать или удалять конфигурации во время выполнения, пользователь должен иметь разрешение безопасности ui.filter.modifyConfiguration.

Чтобы открыть экран Configuration editor, используйте действие Edit всплывающей кнопки настроек фильтра(6).

filter run time configuration

Поле Configuration name обязательно для заполнения. В нем необходимо задать имя конфигурации, отображаемое в выпадающем меню(2) сохраненных фильтров и конфигураций.

С помощью флажка Available for all users можно установить фильтр, доступный для всех пользователей. Этот флажок доступен только пользователям, имеющим разрешение ui.filter.modifyGlobalConfiguration.

С помощью флажка Default for all users можно указать, будет ли созданная конфигурация автоматически выбираться при открытии пользователями экрана. Этот флажок доступен, если установлен флажок Available for all users.

Другие поля Configuration editor описаны в разделе Группирующие условия.

Элементы Filter

Определенный в XML-дескрипторе filter может содержать вложенные элементы. Все они описывают условия, доступные пользователю для выбора в диалоге Add Condition:

properties

properties позволяет сделать доступными для выбора сразу несколько атрибутов сущности. Данный элемент может иметь следующие атрибуты:

  • include - обязательный атрибут, содержит регулярное выражение, которому должно соответствовать имя атрибута сущности.

  • exclude - содержит регулярное выражение, при соответствии которому атрибут сущности исключается из ранее включенных с помощью include.

  • excludeProperties - содержит список атрибутов, разделенных запятыми, которые должны быть исключены из фильтрации. В отличие от exclude, этот атрибут поддерживает путь по графу сущностей для указания каждого свойства в списке. Например, customer.name.

  • excludeRecursively - указывает, должны ли атрибуты, перечисленные в excludeProperties, быть рекурсивно исключены из полного графа сущностей. Если установлено true, указанный атрибут и все его вложенные атрибуты не будут использоваться в фильтре.

В примере ниже объявим компонент filter со вложенным элементом properties:

<filter id="filterWithProperties"
        dataLoader="customersDl">
    <properties include=".*"
                exclude="(hobby)|(age)"
                excludeProperties="id"
                excludeRecursively="true"/>
</filter>

You can exclude or include dynamic attributes, using the attribute’s code with a + prefix, for example:

<filter id="filter"
        dataLoader="carsDl">
    <properties include=".*"
                excludeProperties="+PassengerNumberofseats"/>
</filter>

It is not necessary to have a dynamicAttributes facet on the screen.

Pay attention, if the dynamic attribute is an entity, then the entity’s internal attributes will not be available for filtering.

При использовании элемента properties автоматически игнорируются следующие атрибуты сущности:

  • Недоступные в связи с разрешениями подсистемы безопасности.

  • Коллекции (@OneToMany, @ManyToMany).

  • Коллекции.

  • Атрибуты, аннотированные @SystemLevel.

  • Атрибуты типа byte[].

conditions

Элемент conditions используется для создания предопределенных условий.

В примере ниже объявим компонент filter со вложенным элементом conditions:

<filter id="filterWithСonditions"
        dataLoader="customersDl">
    <properties include=".*"/>
    <conditions>
        <propertyFilter property="hobby"
                        operation="NOT_IN_LIST"
                        operationEditable="true"
                        caption="Hobby condition"/>
    </conditions>
</filter>

Элемент conditions может содержать любое количество propertyFilter, jpqlFilter или groupFilter.

configurations

Элемент configurations используется для создания конфигураций во время разработки.

actions

actions – это необязательный элемент, определяющий список действий для управления фильтрами.

Фреймворк предоставляет следующие действия по умолчанию во всплывающей кнопке настройки фильтра (6) filter settings popup:

  • Save - реализовано с помощью FilterSaveAction (type="filter_save" в XML), сохраняет изменения в текущей конфигурации фильтра.

  • Save with values - реализовано с помощью FilterSaveWithValuesAction (type="filter_saveWithValues" в XML), сохраняет изменения в текущем фильтре, используя значения в полях условия(5) в качестве значений фильтра по умолчанию.

  • Save as - реализовано с помощью FilterSaveAsAction (type="filter_saveAs" в XML), сохраняет конфигурацию фильтра под новым именем.

  • Remove - реализовано с помощью FilterRemoveAction (type="filter_remove" в XML), удаляет текущую конфигурацию фильтра во время выполнения. Отключено для конфигураций во время разработки.

  • Make default - реализовано с помощью FilterMakeDefaultAction (type="filter_makeDefault" в XML), делает конфигурацию фильтра конфигурацией по умолчанию для этого экрана. Фильтр будет автоматически отображен на панели фильтров при открытии экрана. Имеет приоритет над атрибутом default конфигурации во время разработки и флажком Default for all users конфигурации во время выполнения. Отключено, если в экран не добавлен фасет screenSettings.

  • Copy - реализовано с помощью FilterCopyAction (type="filter_copy" в XML), копирует все условия из конфигурации во время разработки в конфигурацию во время выполнения.

  • Clear values - реализовано с помощью FilterClearValuesAction (type="filter_clearValues" в XML), очищает значения условия фильтра(5).

  • Add реализовано с помощью FilterAddConditionAction (type="filter_addCondition" в XML), добавляет условие к текущей конфигурации фильтра.

Пользователи могут переопределять действия default с помощью вложенного элемента actions. Например:

<filter id="filterWithActions"
        dataLoader="customersDl">
    <properties include=".*"/>
    <actions>
        <action id="addCondition" type="filter_addCondition"/>
        <action id="clearValues" type="filter_clearValues"/>
    </actions>
</filter>

Общие параметры действий можно настроить, используя XML-атрибуты элемента action; подробности см. в разделе Действия.

Атрибуты Filter

autoApply

Атрибут autoApply определяет, когда применяется фильтр. Если значение атрибута false, фильтр будет применен только после нажатия кнопки Refresh. Если значение атрибута true, фильтр применяется сразу после изменения компонентов фильтра. Значение по умолчанию указано в свойстве jmix.ui.component.filter-auto-apply.

columnsCount

Параметр columnsCount задает количество столбцов, которые будут отображаться в одной строке. Значение по умолчанию указано в свойстве jmix.ui.component.filter-columns-count.

captionPosition

Атрибут captionPosition определяет положение заголовка дочерних компонентов фильтра: TOP или LEFT. Значение по умолчанию – LEFT.

Разрешения

Для расширенного управления фильтрами требуются специальные разрешения:

  • Для создания/изменения/удаления конфигураций фильтра пользователь должен иметь разрешение ui.filter.modifyConfiguration.

  • Для создания/изменения условий JPQL во время выполнения пользователь должен иметь разрешение ui.filter.modifyJpqlCondition.

Вы можете либо предоставить пользователям предопределенную ресурсную роль UI: edit filters, либо настроить необходимые разрешения в своей собственной роли.

Свойства приложения

Следующие свойства приложения влияют на поведение фильтров:

Creating Filter Programmatically

In the example below, we will create the Filter component with a design-time configuration and add this filter to the tab, defined in the XML descriptor.

To create the Filter component in the controller, use the UiComponents factory.

@Autowired
protected UiComponents uiComponents;

@Autowired
protected CollectionLoader<Customer> customersDl;

@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onAfterInit(AfterInitEvent event) {
    Filter filter = uiComponents.create(Filter.NAME); (1)
    filter.setId("programmaticFilter");
    filter.setDataLoader(customersDl);
    filter.loadConfigurationsAndApplyDefault();

    DesignTimeConfiguration javaDefaultConfiguration =
            filter.addConfiguration("javaDefaultConfiguration",
                    "Default configuration"); (2)

    PropertyFilter<Integer> agePropertyFilter =
            uiComponents.create(PropertyFilter.NAME); (3)

    agePropertyFilter.setConditionModificationDelegated(true);
    agePropertyFilter.setDataLoader(customersDl);
    agePropertyFilter.setProperty("age");
    agePropertyFilter.setOperation(PropertyFilter.Operation.LESS_OR_EQUAL);
    agePropertyFilter.setOperationEditable(true);
    agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            agePropertyFilter.getProperty()));
    agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            customersDl.getContainer().getEntityMetaClass(),
            agePropertyFilter.getProperty(),
            agePropertyFilter.getOperation())); (4)

    javaDefaultConfiguration.getRootLogicalFilterComponent().add(agePropertyFilter); (5)
    filter.setCurrentConfiguration(javaDefaultConfiguration); (6)

    VBoxLayout tab = (VBoxLayout) getWindow()
            .getComponentNN("programmaticFilterTab"); (7)
    tab.add(filter); (8)
}
1 Creates Filter and sets its properties.
2 Adds a design-time configuration with the javaDefaultConfiguration id and the Default configuration name.
3 Creates PropertyFilter and sets its properties.
4 Generates the filter value component by the given metaClass, entity property and operation.
5 Adds the created property filter to the javaDefaultConfiguration configuration.
6 Sets the javaDefaultConfiguration configuration as current.
7 Gets the tab by its id.
8 Adds the created Filter component to the programmaticFilterTab tab.

События и слушатели

Чтобы сгенерировать заглушку слушателя в Jmix Studio, выберите компонент в XML-дескрипторе экрана или на панели Component Hierarchy и используйте вкладку Handlers панели Component Inspector.

В качестве альтернативы вы можете воспользоваться кнопкой Generate Handler на верхней панели контроллера экрана.

ContextHelpIconClickHandler

ExpandedStateChangeEvent

ConfigurationChangeEvent

ConfigurationChangeEvent отправляется при изменении конфигурации. Пример подписки на событие фильтра, объявленного в XML с идентификатором filter:

@Subscribe("filter")
public void onFilterConfigurationChange(Filter.ConfigurationChangeEvent event) {
    notifications.create()
            .withCaption("Before: " + event.getPreviousConfiguration().getName() +
                    ". After: " + event.getNewConfiguration().getName())
            .show();
}

Чтобы создать слушателя события программно, используйте метод компонента addConfigurationChangeListener().

PropertiesFilterPredicate

Чтобы включать или исключать свойства из фильтрации программно, используйте PropertiesFilterPredicate:

@Install(to = "filter", subject = "propertiesFilterPredicate")
private boolean filterPropertiesFilterPredicate(MetaPropertyPath metaPropertyPath) {
    return !metaPropertyPath.getMetaProperty().getName().equals("hobby");
}

Этот предикат добавляется к текущему предикату фильтра properties и проверяет, должно ли свойство с заданным путем быть доступным для фильтрации.

Чтобы добавить предикат программно, используйте метод компонента addPropertiesFilterPredicate(). Результирующий предикат является составным предикатом, представляющий логическое замыкание AND заданного предиката и предиката текущего фильтра properties.

Все XML-атрибуты

Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели Component Inspector конструктора экранов Studio.

XML-элементы Filter