Filtering and Sorting¶
Mobile Development Kit Client provides two approaches for filtering and sorting list content on a Section Page: a table-level solution using FilterFeedbackBar on SectionedTable, and a section-level solution using FilterBar on individual sections. FilterBar is available as of version 26.6. Both approaches cannot coexist on the same page — if both are defined, FilterBar takes priority.
Table-Level Filtering: FilterFeedbackBar¶
FilterFeedbackBar is a horizontal chip bar displayed above the list content of a SectionedTable. It shows active filters and lets users quickly toggle frequently used filter options.
Placement and layout:
- Define
FilterFeedbackBaronSectionedTable. - It appears below the navigation bar and below the search bar, if a search bar is present.
- The bar is horizontally scrollable when chips do not fit on screen.
- On iOS,
FilterFeedbackBaris not shown when the first section isObjectHeader.
Use FilterFeedbackBar when users frequently apply a small set of common filters across the entire table.
Fast Filters¶
Fast filters are predefined filter or sorter chips displayed directly on FilterFeedbackBar. Each fast filter item must define:
FilterType—FilterorSorterReturnValue
Query behavior depends on how you configure the item:
FilterPropertyset: MDK builds a simple query automatically, for example,FilterProperty eq ReturnValue.FilterPropertynot set:ReturnValueis treated as a full custom expression and used directly, for example,quantity ge 5.CustomQueryGroupset: Fast filter items with the same group are combined with theORoperator. Different groups and ungrouped items are combined with theANDoperator. When the_Nameof a fast filter item matches aCustomQueryGroupvalue, it can be aligned with Filter page controls.
The following example shows a complete FilterFeedbackBar configuration with sorter and filter fast filter items, including a CustomQueryGroup for OR-combined filters:
"FilterFeedbackBar": {
"ShowAllFilters": "true",
"FastFilters": [
{
"_Name": "OrderByOrderId",
"FilterType": "Sorter",
"Label": "Order By",
"DisplayValue": "Order Id",
"ReturnValue": "OrderId"
},
{
"_Name": "OrderByBA",
"FilterType": "Sorter",
"DisplayValue": "Business Area",
"ReturnValue": "BusinessArea"
},
{
"_Name": "LowPriority",
"FilterType": "Filter",
"Label": "Prio",
"FilterProperty": "Priority",
"DisplayValue": "Low",
"ReturnValue": "1"
},
{
"_Name": "IDFilterLt",
"FilterType": "Filter",
"FilterProperty": "",
"CustomQueryGroup": "OrderIdGroup",
"Label": "ID",
"DisplayValue": "< 4000020",
"ReturnValue": "OrderId lt '4000020'"
},
{
"_Name": "IDFilterGt",
"FilterType": "Filter",
"FilterProperty": "",
"CustomQueryGroup": "OrderIdGroup",
"Label": "",
"DisplayValue": "> 4000020",
"ReturnValue": "OrderId gt '4000020'"
}
],
"Styles": {
"Active": "activeFilter",
"InActive": "inactiveFilter"
}
}
Filter Counter Chip¶
FilterFeedbackBar supports an optional filter counter chip. It can be added after the user activates a filter chip, and is placed in front of the first filter chip to display the total number of active items in the filter. Once the filter is applied, the total number of items in the list is returned.
Synchronization with Filter Page¶
FilterFeedbackBar and Filter page selections are synchronized through SectionedTable.Filters. Selecting filters on either side updates the shared filter result.
Fast filter items and Filter page controls do not need to be identical. If both sides use completely different items, synchronization still runs but may have no visible effect.
You can display selected Filter page values as ad-hoc chips on FilterFeedbackBar by setting FilterFeedbackBar.ShowAllFilters to true. An ad-hoc chip remains selected while its Filter page value is active and is removed when deselected from either side.
Default Filters for FilterFeedbackBar¶
Runtime APIs for FilterFeedbackBar¶
filters(getter) — returns the currentFilterCriteria[]filters(setter) — updates the current filters and synchronizesFilterFeedbackBarand the Filter pagegetFilterActionResult()— returns the current$filterquery stringgetSorterActionResult()— returns the current$orderbyquery string
Section-Level Filtering: FilterBar¶
FilterBar is similar to FilterFeedbackBar but scoped to an individual section. Define it on a section, not on SectionedTable. A page can have multiple sections, each with its own FilterBar.
Placement and layout:
FilterBarappears below the section header.- If there is only one section, the bar stays sticky — it remains at the top regardless of how far the user scrolls.
- With multiple sections, the bar scrolls with the section content.
Unlike FilterFeedbackBar, FilterBar supports control-driven interactions through a bottom sheet or modal dialog. On tablet devices, the sheet appears as a centered dialog (Android) or a side panel (iOS).
Supported Sections¶
FilterBar can be defined on the following section types:
ObjectTable,ObjectCollection,ContactTable,DataTableCardCollection,ObjectCardCollectionGridTable(Android only)
Sections and Controls Structure¶
FilterBar is organized into Sections, each containing a Controls array. Controls within the same section are combined with the AND operator. Controls in different sections are independent.
Each control must have a _Type and a _Name. The _Name is used to reference the control in the Filters rule and runtime APIs.
The following example shows a complete FilterBar configuration with all supported control types:
"FilterBar": {
"_Type": "Control.Type.FilterBar",
"_Name": "SortFilterBar",
"Filters": "/MDKApp/Rules/FilterBar/InitialFilters.js",
"Sections": [
{
"Controls": [
{
"_Name": "Priority",
"_Type": "FilterBar.Type.Segmented",
"Label": "Priority",
"Value": "",
"Items": [
{ "DisplayValue": "Low", "ReturnValue": "1" },
{ "DisplayValue": "Medium", "ReturnValue": "2" },
{ "DisplayValue": "High", "ReturnValue": "3" }
],
"SimpleQuery": { "Property": "Priority", "Operator": "eq" },
"DisplayOnBar": false
},
{
"_Name": "OrderIdCompare",
"_Type": "FilterBar.Type.Segmented",
"Label": "OrderID Compare",
"Value": "",
"Items": [
{ "DisplayValue": "< 4004760", "ReturnValue": "OrderId lt '4004760'" },
{ "DisplayValue": "= 4004760", "ReturnValue": "OrderId eq '4004760'" },
{ "DisplayValue": "> 4004760", "ReturnValue": "OrderId gt '4004760'" }
],
"AllowEmptySelection": true,
"AllowMultipleSelection": false,
"DisplayOnBar": true
},
{
"_Name": "OrderIdGt",
"_Type": "FilterBar.Type.ListPicker",
"Label": "Order ID >=",
"Value": "4000034",
"PickerItems": {
"DisplayValue": "{OrderDescription}",
"ReturnValue": "{OrderId}",
"Target": {
"EntitySet": "MyWorkOrderHeaders",
"Service": "/MDKApp/Services/Amw.service",
"QueryOptions": "$top=20"
}
},
"Search": { "Enabled": true },
"AllowMultipleSelection": false,
"AllowEmptySelection": true,
"SimpleQuery": { "Property": "OrderId", "Operator": "ge" },
"DisplayOnBar": true
}
]
},
{
"Controls": [
{
"_Name": "Favorite",
"_Type": "FilterBar.Type.Switch",
"Label": "Is Favorite?",
"HelperText": "Favorite is",
"SimpleQuery": { "Property": "Favorite" },
"DisplayOnBar": true
},
{
"_Name": "Quantity",
"_Type": "FilterBar.Type.Slider",
"Label": "Qty",
"MinValue": 1,
"MaxValue": 100,
"DecimalPlaces": 1,
"HelperText": "Quantity is",
"SimpleQuery": { "Property": "Quantity", "Operator": "ge" },
"DisplayOnBar": true
}
]
},
{
"Controls": [
{
"_Name": "MultiSorter",
"_Type": "FilterBar.Type.MultiSorter",
"Label": "Multi sorter",
"Value": "",
"Items": [
{ "ReturnValue": "OrderId", "DisplayValue": "Order Id", "AscendingLabel": "ascending", "DescendingLabel": "descending" },
{ "ReturnValue": "Priority", "DisplayValue": "Priority", "AscendingLabel": "asc", "DescendingLabel": "desc" },
{ "ReturnValue": "CreationDate", "DisplayValue": "Created On", "AscendingLabel": "Earliest first","DescendingLabel": "Latest first" },
{ "ReturnValue": "DueDate", "DisplayValue": "Due Date", "AscendingLabel": "Earliest first","DescendingLabel": "Latest first" }
],
"HelperText": "Sort by",
"DisplayOnBar": true
}
]
}
],
"Styles": {
"Bar": "filterBarClass",
"Active": "activeFilterBarItemClass",
"InActive": "inactiveFilterBarItemClass"
}
}
Supported Controls¶
FilterBar supports the following controls:
SegmentedListPickerSwitchSliderMultiSorter
Most controls display a downward chevron to open a bottom sheet or popover. Switch is the exception — it does not open a sheet. The DisplayOnBar property controls whether a control appears directly on the bar (default: true). All defined controls are also available in the filter dialog.
Segmented displays a set of mutually exclusive option buttons. AllowMultipleSelection (default: true) enables multi-select. AllowEmptySelection (default: true) allows deselecting all options — on Android, this is always true regardless of configuration.
ListPicker displays a scrollable list of items. Set Search.Enabled to true to add a search field within the picker. PickerItems supports both fixed collections and entity set target binding. As with Segmented, AllowEmptySelection is always true on Android.
Slider renders a range slider. Key properties: MinValue (default: 0), MaxValue (default: 100), Step (default: 1), DecimalPlaces. Slider supports only numeric properties and does not support complex query expressions.
Switch renders a toggle. It filters on boolean properties only and does not support complex query expressions. When toggled on, the value is true; when toggled off, the filter is not applied.
MultiSorter displays a list of sortable criteria with checkboxes and drag handles, allowing users to select multiple criteria and reorder them to set sort priority. Each item supports AscendingLabel and DescendingLabel to display contextual sort direction labels (for example, "Earliest first" instead of "Ascending").
Query Configuration¶
- Use
SimpleQuery.Property(and optionalSimpleQuery.Operator) for automatic query generation. Supported operators areeq(default),ne,gt,ge,lt, andle. - For complex scenarios where different items represent different properties or operators, omit
SimpleQueryand provide a full OData expression inReturnValuedirectly, for example"ReturnValue": "OrderId ge '4000034'". SwitchandSliderdo not support complex query expressions — they can only filter on boolean and numeric properties respectively.
Relationship to FilterFeedbackBar and Filter Page¶
FilterBar does not synchronize with table-level filtering.
- No synchronization exists between a section
FilterBarandSectionedTable.FilterFeedbackBar. - If a Filter page or
SectionedTable.Filtersis also used, those filters act as a base query andFilterBarfilters are applied on top.
Default Filters for FilterBar¶
Define initial section filter state in FilterBar.Filters. The rule must return an array of FilterSelection. Use createFilterSelection and createSorterSelection APIs to build FilterSelection objects.
FilterBar.Filters takes precedence over a control's Value property when both target the same control. This makes Filters the recommended approach for programmatic filter resets.
export default function InitialFilters(context) {
let initialSelections = [
context.createFilterSelection('ControlA', ['NewValueA']),
context.createFilterSelection('ControlB', ['NewValueB'])
];
return initialSelections;
}
Runtime APIs for FilterBar¶
SectionProxy APIs:
getFilterBar()— returns theFilterBarProxyfor the sectionfilters(getter) — returns the currentFilterSelection[]setFilters(...)(returns a Promise) — updates the currentFilterBarselections; use together withFilterBar.Filtersas a single source of truth for manual resetsfilterBarFilterQuery— returns the current$filterquery stringfilterBarSorterQuery— returns the current$orderbyquery string
Context/ClientAPI (available to all proxies):
createFilterSelection(name: string, values: Array<object>): FilterSelection— creates a filter selection for the control identified bynamecreateSorterSelection(name: string, values: Array<object>): FilterSelection— creates a sorter selection for the control identified byname