Skip to content

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 FilterFeedbackBar on SectionedTable.
  • 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, FilterFeedbackBar is not shown when the first section is ObjectHeader.

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:

  • FilterTypeFilter or Sorter
  • ReturnValue

Query behavior depends on how you configure the item:

  • FilterProperty set: MDK builds a simple query automatically, for example, FilterProperty eq ReturnValue.
  • FilterProperty not set: ReturnValue is treated as a full custom expression and used directly, for example, quantity ge 5.
  • CustomQueryGroup set: Fast filter items with the same group are combined with the OR operator. Different groups and ungrouped items are combined with the AND operator. When the _Name of a fast filter item matches a CustomQueryGroup value, 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 current FilterCriteria[]
  • filters (setter) — updates the current filters and synchronizes FilterFeedbackBar and the Filter page
  • getFilterActionResult() — returns the current $filter query string
  • getSorterActionResult() — returns the current $orderby query 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:

  • FilterBar appears 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, DataTable
  • CardCollection, ObjectCardCollection
  • GridTable (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:

  • Segmented
  • ListPicker
  • Switch
  • Slider
  • MultiSorter

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 optional SimpleQuery.Operator) for automatic query generation. Supported operators are eq (default), ne, gt, ge, lt, and le.
  • For complex scenarios where different items represent different properties or operators, omit SimpleQuery and provide a full OData expression in ReturnValue directly, for example "ReturnValue": "OrderId ge '4000034'".
  • Switch and Slider do 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 FilterBar and SectionedTable.FilterFeedbackBar.
  • If a Filter page or SectionedTable.Filters is also used, those filters act as a base query and FilterBar filters 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 the FilterBarProxy for the section
  • filters (getter) — returns the current FilterSelection[]
  • setFilters(...) (returns a Promise) — updates the current FilterBar selections; use together with FilterBar.Filters as a single source of truth for manual resets
  • filterBarFilterQuery — returns the current $filter query string
  • filterBarSorterQuery — returns the current $orderby query string

Context/ClientAPI (available to all proxies):

  • createFilterSelection(name: string, values: Array<object>): FilterSelection — creates a filter selection for the control identified by name
  • createSorterSelection(name: string, values: Array<object>): FilterSelection — creates a sorter selection for the control identified by name

Last update: June 23, 2026