Filter Components
Filter can use special filter components as conditions. Filter components should implement the FilterComponent
interface.
There are three filter components available by default:
You can register your own filter component, see Filter Component Registration.
PropertyFilter
The PropertyFilter
component can be used inside the Filter
component and independently.
The example below demonstrates how to create a design-time configuration with PropertyFilter
in the XML descriptor:
<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"
id="filterPropertyFilter"
caption="PropertyFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="propertyConfiguration"
default="true"
name="PropertyFilter">
<propertyFilter property="age"
operation="GREATER_OR_EQUAL"
operationEditable="true"/>
</configuration>
</configurations>
</filter>
</layout>
You can also create a design-time configuration in the screen controller class:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationPF =
pfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderPF = pfdtcFilter.getDataLoader();
PropertyFilter<City> cityPropertyFilter =
uiComponents.create(PropertyFilter.NAME); (2)
cityPropertyFilter.setConditionModificationDelegated(true);
cityPropertyFilter.setDataLoader(dataLoaderPF);
cityPropertyFilter.setProperty("city");
cityPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
cityPropertyFilter.setOperationEditable(true);
cityPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
cityPropertyFilter.getProperty()));
cityPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderPF.getContainer().getEntityMetaClass(),
cityPropertyFilter.getProperty(),
cityPropertyFilter.getOperation())); (3)
javaDefaultConfigurationPF.getRootLogicalFilterComponent()
.add(cityPropertyFilter); (4)
PropertyFilter<Level> levelPropertyFilter =
uiComponents.create(PropertyFilter.NAME);
levelPropertyFilter.setConditionModificationDelegated(true);
levelPropertyFilter.setDataLoader(dataLoaderPF);
levelPropertyFilter.setProperty("level");
levelPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
levelPropertyFilter.setOperationEditable(true);
levelPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
levelPropertyFilter.getProperty()));
levelPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderPF.getContainer().getEntityMetaClass(),
levelPropertyFilter.getProperty(),
levelPropertyFilter.getOperation()
));
javaDefaultConfigurationPF.getRootLogicalFilterComponent().add(levelPropertyFilter);
pfdtcFilter.setCurrentConfiguration(javaDefaultConfigurationPF); (5)
}
1 | Adds a design-time configuration with the javaDefaultConfiguration id and the Default configuration name. |
2 | Creates the PropertyFilter component and sets its properties. |
3 | Generates the filter value component by the given metaClass, entity property and operation. |
4 | Adds the created property filter to the javaDefaultConfiguration configuration. |
5 | Sets the javaDefaultConfiguration configuration as current. |
See the additional information in PropertyFilter.
JpqlFilter
JpqlFilter
is a UI component used for filtering entities returned by the DataLoader
. The component contains JPQL expressions that will be added to the from
and where
data loader query sections. The component can automatically render the proper layout for setting a condition value. A JpqlFilter
layout contains a label with a caption and a field for editing a condition value in the general case. The component can be used only inside the Filter
component.
The example below demonstrates how to create a design-time configuration with a JpqlFilter
:
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://filterScreen.caption"
xmlns:c="http://jmix.io/schema/ui/jpql-condition"> (1)
<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 id="filterJpqlFilter"
dataLoader="customersDl"
caption="JpqlFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfiguration"
default="true"
name="JpqlFilter">
<jpqlFilter caption="Name like"
parameterClass="java.lang.String">
<condition>
<c:jpql>
<c:where>{E}.firstName like ?</c:where> (2)
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
</layout>
</window>
1 | You should add the JPQL conditions namespace. |
2 | Define a JPQL condition with optional join element and mandatory where element. |
To configure JPQL conditions, define the condition
element inside jpqlFilter
with optional join element and mandatory where element. In the example below, we create jpqlFilter
with the join
and where
elements:
<filter id="filterJpqlFilter"
dataLoader="customersDl"
caption="JpqlFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfigurationWithJoin"
name="JpqlFilter with Join">
<jpqlFilter caption="Customers with brand"
parameterClass="ui.ex1.entity.Brand">
<condition>
<c:jpql>
<c:join>join {E}.favouriteBrands i</c:join>
<c:where>i.id = ?</c:where>
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
jpqlFilter
attributes inside the filter
component:
-
You can use the
defaultValue
attribute to set the default value for the filter condition.
-
The
hasInExpression
attribute should be set totrue
if the JPQL expression containsin (?)
conditions. In this case, the application will use the ValuesPicker component. So the user will be able to enter several condition parameter values.Below is an example of
jpqlFilter
with thehasInExpression
attribute:<filter id="filterJpqlFilter" dataLoader="customersDl" caption="JpqlFilter variations"> <properties include=".*"/> <configurations> <configuration id="jpqlConfigurationInExpr" name="JpqlFilter with IN expression"> <jpqlFilter caption="City in" parameterClass="ui.ex1.entity.City" hasInExpression="true"> <condition> <c:jpql> <c:where>{E}.city in ?</c:where> </c:jpql> </condition> </jpqlFilter> </configuration> </configurations> </filter>
-
parameterClass
is a required attribute; it defines the Java class of the condition parameter.
-
parameterName
- the name of the associated query parameter. You can use this name to introduce dependencies between filter components in configuration. If not defined, then the parameter name is randomly generated.
You can also create a design-time configuration in the screen controller class:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationJF =
jfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderJF = jfdtcFilter.getDataLoader();
JpqlFilter<Brand> jpqlFilter =
uiComponents.create(JpqlFilter.NAME); (2)
jpqlFilter.setFrame(getWindow());
jpqlFilter.setConditionModificationDelegated(true);
jpqlFilter.setDataLoader(dataLoaderJF);
jpqlFilter.setCondition("i.id = ?", "join {E}.favouriteBrands i");
jpqlFilter.setParameterClass(Brand.class);
jpqlFilter.setCaption("Select the brand");
jpqlFilter.setParameterName(jpqlFilterSupport.generateParameterName(
jpqlFilter.getId(),
jpqlFilter.getParameterClass().getSimpleName()));
jpqlFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderJF.getContainer().getEntityMetaClass(),
jpqlFilter.hasInExpression(),
jpqlFilter.getParameterClass())); (3)
javaDefaultConfigurationJF.getRootLogicalFilterComponent()
.add(jpqlFilter); (4)
jfdtcFilter.setCurrentConfiguration(javaDefaultConfigurationJF); (5)
}
1 | Adds a design-time configuration with the javaDefaultConfiguration id and the Default configuration name. |
2 | Creates the JpqlFilter component and sets its properties. |
3 | Generates the filter value component by the given metaClass, and value type. |
4 | Adds the created jpql filter to the javaDefaultConfiguration configuration. |
5 | Sets the javaDefaultConfiguration configuration as current. |
Filter without Parameters
It is possible to define a query without parameters. To do so, set the parameterClass
value to java.lang.Void
, and use java.lang.Boolean
as a value:
-
true
value means that JPQL expressions fromwhere
andjoin
sections will be added to the data loader query. -
false
will not load expressions fromwhere
andjoin
sections.
Example:
<filter id="parameterlessFilter"
dataLoader="customersDl"
caption="JPQL Filter without Parameters">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfigurationNoParams"
name="JPQL Filter without Parameters">
<jpqlFilter caption="Customers from London"
parameterClass="java.lang.Void"
defaultValue="true"> (1)
<condition>
<c:jpql>
<c:join>join {E}.city c</c:join> (2)
<c:where>c.name = 'London'</c:where>
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
1 | parameterClass="java.lang.Void" makes the filter parameterless, and defaultValue="true" defines that the join and where expressions will be added to the data loader query by default. |
2 | Define a JPQL condition with optional join element and mandatory where element. |
Below is an example of creating a parameterless JPQL filter in the screen controller class:
@Autowired
private Filter parameterlessFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaConfiguration = parameterlessFilter
.addConfiguration("javaConfiguration", "Java configuration");
DataLoader dataLoader = parameterlessFilter.getDataLoader();
JpqlFilter<Boolean> jpqlFilterNoParams = uiComponents.create(JpqlFilter.NAME);
jpqlFilterNoParams.setFrame(getWindow());
jpqlFilterNoParams.setConditionModificationDelegated(true);
jpqlFilterNoParams.setDataLoader(dataLoader);
jpqlFilterNoParams.setCondition("{E}.age > 21", null);
jpqlFilterNoParams.setParameterClass(Void.class);
jpqlFilterNoParams.setCaption("Customer's age > 21");
jpqlFilterNoParams.setParameterName(jpqlFilterSupport
.generateParameterName(jpqlFilterNoParams.getId(),
jpqlFilterNoParams.getParameterClass().getSimpleName()));
jpqlFilterNoParams.setValueComponent(singleFilterSupport
.generateValueComponent(dataLoader.getContainer().getEntityMetaClass(),
jpqlFilterNoParams.hasInExpression(),
jpqlFilterNoParams.getParameterClass()
));
jpqlFilterNoParams.setValue(true);
javaConfiguration.setFilterComponentDefaultValue(
jpqlFilterNoParams.getParameterName(),
jpqlFilterNoParams.getValue());
javaConfiguration.getRootLogicalFilterComponent().add(jpqlFilterNoParams);
jpqlFilterNoParams.setValue(true);
javaConfiguration.setFilterComponentDefaultValue(
jpqlFilterNoParams.getParameterName(),
jpqlFilterNoParams.getValue());
javaConfiguration.getRootLogicalFilterComponent().add(jpqlFilterNoParams);
}
The JPQL filter configuration without parameters can also be created at run-time:
GroupFilter
The GroupFilter
component is a composite component that has a GroupBoxLayout with a ResponsiveGridLayout as its root container. This component is needed to combine several conditions into a logical group, using logical operators (AND
or OR
). The component can be used only inside the Filter
component.
The example below demonstrates how to create a design-time configuration with a GroupFilter
:
<filter id="filterGroupFilter"
dataLoader="customersDl"
caption="GroupFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="groupFilter"
name="Simple groupFilter"
default="true">
<groupFilter operation="OR">
<propertyFilter property="age"
operation="GREATER_OR_EQUAL"
operationEditable="true"/>
<propertyFilter property="city"
operation="EQUAL"
operationEditable="true"/>
</groupFilter>
</configuration>
</configurations>
</filter>
The operation
attribute is required. Two logical operations are available:
-
AND
is the default operation -
OR
You can also create a design-time configuration in the screen controller class:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationGF =
gfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderGF = gfdtcFilter.getDataLoader();
GroupFilter groupFilter =
uiComponents.create(GroupFilter.NAME); (2)
groupFilter.setConditionModificationDelegated(true);
groupFilter.setDataLoader(dataLoaderGF);
groupFilter.setOperation(LogicalFilterComponent.Operation.OR); (3)
PropertyFilter<Integer> pointsPropertyFilter =
uiComponents.create(PropertyFilter.NAME); (4)
pointsPropertyFilter.setConditionModificationDelegated(true);
pointsPropertyFilter.setDataLoader(dataLoaderGF);
pointsPropertyFilter.setProperty("rewardPoints");
pointsPropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
pointsPropertyFilter.setOperationEditable(true);
pointsPropertyFilter.setParameterName(PropertyConditionUtils
.generateParameterName(pointsPropertyFilter.getProperty()));
pointsPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderGF.getContainer().getEntityMetaClass(),
pointsPropertyFilter.getProperty(),
pointsPropertyFilter.getOperation()));
groupFilter.add(pointsPropertyFilter); (5)
PropertyFilter<Hobby> hobbyPropertyFilter =
uiComponents.create(PropertyFilter.NAME);
hobbyPropertyFilter.setConditionModificationDelegated(true);
hobbyPropertyFilter.setDataLoader(dataLoaderGF);
hobbyPropertyFilter.setProperty("hobby");
hobbyPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
hobbyPropertyFilter.setOperationEditable(true);
hobbyPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
hobbyPropertyFilter.getProperty()));
hobbyPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderGF.getContainer().getEntityMetaClass(),
hobbyPropertyFilter.getProperty(),
hobbyPropertyFilter.getOperation()
));
groupFilter.add(hobbyPropertyFilter); (6)
javaDefaultConfigurationGF.getRootLogicalFilterComponent().add(groupFilter); (7)
PropertyFilter<Integer> agePropertyFilter =
uiComponents.create(PropertyFilter.NAME);
agePropertyFilter.setConditionModificationDelegated(true);
agePropertyFilter.setDataLoader(dataLoaderGF);
agePropertyFilter.setProperty("age");
agePropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
agePropertyFilter.setOperationEditable(true);
agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
agePropertyFilter.getProperty()));
agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderGF.getContainer().getEntityMetaClass(),
agePropertyFilter.getProperty(),
agePropertyFilter.getOperation()
));
javaDefaultConfigurationGF.getRootLogicalFilterComponent().add(agePropertyFilter);
pointsPropertyFilter.setValue(1000);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
pointsPropertyFilter.getParameterName(), 1000); (8)
hobbyPropertyFilter.setValue(Hobby.FISHING);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
hobbyPropertyFilter.getParameterName(), Hobby.FISHING);
agePropertyFilter.setValue(30);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
agePropertyFilter.getParameterName(), 30);
}
1 | Adds a design-time configuration with the javaDefaultConfiguration id and the Default configuration name. |
2 | Creates the GroupFilter component and sets its properties. |
3 | Sets the OR logical operation for groupFilter . |
4 | Creates the PropertyFilter component and sets its properties. |
5 | Adds pointsPropertyFilter to groupFilter . |
6 | Adds hobbyPropertyFilter to groupFilter . |
7 | Adds the created group filter to the javaDefaultConfiguration configuration. |
8 | Sets a default value of pointsPropertyFilter for the javaDefaultConfiguration configuration by the parameter name. |
Filter Component Registration
To create and register a UI filter component in the framework, you need the following objects:
-
A component class - a UI component that will be displayed inside the
Filter
component. A component class should extend theFilterComponent
class. As an example of a component class, consider thePropertyFilter
class. -
A model class - a non-persistent class that stores the state of the filter component. A model class is used to save the filter component state in DB and display and change the state of the filter component at run-time. A model class should extend the
FilterCondition
class. As an example of a model class, consider thePropertyFilterCondition
class. -
A converter class is needed for converting between a component and a model. A converter class should implement the
FilterConverter
interface. -
An edit screen - the model edit screen. If no identifier is specified, then the default identifier (for example,
modelName.edit
,PropertyFilterCondition.edit
) will be used.
PropertyFilter
registration example:
@Bean
public FilterComponentRegistration registerPropertyFilter() {
return FilterComponentRegistrationBuilder.create(PropertyFilter.class,
PropertyFilterCondition.class,
PropertyFilterConverter.class)
.withEditScreenId("ui_PropertyFilterCondition.edit")
.build();
}
All registered filter components are displayed in a popup button on the Add Condition
dialog.
You can replace a filter component registered in the Jmix framework with your own implementation by specifying the @Order
annotation on the FilterComponentRegistration
bean (for example, to expand the set of model attributes saved by the filter).
All XML Attributes
You can view and edit attributes applicable to the component using the Component Inspector panel of the Studio’s Screen Designer. |
JpqlFilter XML Attributes
align - caption - captionAsHtml - colspan - contextHelpText - contextHelpTextHtmlEnabled - css - defaultValue - description - descriptionAsHtml - editable - enable - box.expandRatio - hasInExpression - height - htmlSanitizerEnabled - icon - id - parameterClass - parameterName - required - requiredMessage - responsive - rowspan - stylename - tabIndex - visible - width
GroupFilter XML Attributes
align - caption - captionAsHtml - colspan - description - descriptionAsHtml - enable - box.expandRatio - height - htmlSanitizerEnabled - icon - id - operation - operationCaptionVisible - responsive - rowspan - stylename - visible - width