Skip to main content

Filters Reference

Filters allow users to refine the data displayed on an Aptean Mesh page. They are declared in the contract.filters array and rendered in a filter panel (or inline as selector components). When a user changes a filter value, the associated filter action re-fetches data from the AL backend with the updated filter parameters.


FilterDefinition

Each entry in the filters array is a FilterDefinition object. Defined in FilterDefinition.kt as a @Serializable data class.

PropertyTypeDefaultDescription
idstringrequiredUnique identifier for this filter. Used as a parameter key in action params arrays and in data bindings.
labelstringrequiredDisplay label shown next to the filter control.
modeFilterMode"DROPDOWN"The filter input mode. Determines how the filter is rendered. See FilterMode below.
variantSelectorType"DROPDOWN"Visual variant for the filter control. Values: "DROPDOWN" or "SEGMENT". Controls rendering style independently of behavior.
optionsstring[][]Static list of option strings. Use this for filters with a fixed set of choices known at page-authoring time.
optionsKeystring?nullData binding key pointing to a dynamic array of option objects in the page data. The client resolves options from API response data at runtime. Ignored when options is non-empty.
labelKeystring"label"When using optionsKey, the field name within each option object to use as the display label.
valueFieldstring?nullWhen using optionsKey, the field name within each option object to use as the selected value sent to the backend. When null, the label value is used.
defaultValuestring?nullThe initial selected value when the page loads. When null, no option is pre-selected.
segmentKeystring?nullA data context key whose value is overridden when a segment option is selected. Used to drive segment-based navigation or data switching.
segmentMappingobject{}Maps each segment option value to an override value written to segmentKey. Keys are the option display values; values are the data values written to the context.

FilterMode

The FilterMode enum (defined in FilterMode.kt) controls how a filter is rendered and how the user interacts with it.

ValueDescription
DROPDOWNA dropdown picker. The user taps to open a list and selects one option. Best for filters with many options (5+).
SEGMENTA segmented control (horizontal row of buttons). The user taps one segment to select it. Best for filters with 2--4 options.
LOOKUPOpens a lookup modal with a search field. The user can type to filter and then select from a list. Best for large data sets (locations, items, customers).
DATEA date picker. The user selects a date from a calendar or date input. Used for date-range or single-date filters.

Static filters

Static filters use the options array to define a fixed set of choices. These values are known at page-authoring time and do not change at runtime.

{
"filters": [
{
"id": "StatusFilter",
"label": "Status",
"mode": "SEGMENT",
"options": ["All", "Open", "Released", "Completed"],
"defaultValue": "All"
}
]
}

When the user selects "Released", the filter action's params array includes "StatusFilter" and the client sends the value "Released" to the AL backend. In AL, read it with State.GetInput('StatusFilter').


Dynamic filters

Dynamic filters use optionsKey to bind to data returned by an API action. The options are resolved at runtime from the page's data store.

{
"filters": [
{
"id": "LocationFilter",
"label": "Location",
"mode": "DROPDOWN",
"optionsKey": "locations",
"labelKey": "name",
"valueField": "code",
"defaultValue": "ALL"
}
]
}

This filter reads from the locations array in the page data. If the API returns:

{
"locations": [
{ "code": "ALL", "name": "All Locations" },
{ "code": "WH-EAST", "name": "East Warehouse" },
{ "code": "WH-WEST", "name": "West Warehouse" }
]
}

The filter displays "All Locations", "East Warehouse", and "West Warehouse" as options. When the user selects "East Warehouse", the value "WH-EAST" (from valueField) is sent to the backend.

Option resolution logic

The client resolves dynamic options using this logic (from FilterUtils.kt):

  1. If options is non-empty, use it directly (static mode).
  2. Otherwise, if optionsKey is set, look up that key in the page data to get an array of objects.
  3. For each object, extract the display label using labelKey (defaults to "label").
  4. If the object does not contain the labelKey field, fall back to the first value in the object.

Segment filters with mapping

Segment filters can use segmentKey and segmentMapping to override a data context value when the user selects a segment. This is useful for switching between different data views or modes.

{
"filters": [
{
"id": "ViewMode",
"label": "View",
"mode": "SEGMENT",
"options": ["By Zone", "By Item", "By Date"],
"segmentKey": "groupBy",
"segmentMapping": {
"By Zone": "zone",
"By Item": "itemNo",
"By Date": "postingDate"
}
}
]
}

When the user selects "By Item", the value "itemNo" is written to the groupBy key in the data context. The filter action can then include "groupBy" in its params to pass this value to the AL backend.


Connecting filters to actions

Filters work together with filter actions and selectors. The typical setup involves three parts:

  1. A filter definition in contract.filters -- defines the filter's options and behavior.
  2. A filter action in contract.actions -- defines the API endpoint to call when the filter changes.
  3. A selector component in body -- renders the filter control and triggers the action on selection.

Complete example

{
"pageId": "INVENTORY-LIST",
"service": "INVENTORYSERVICE",
"header": {
"title": "Inventory",
"refresh": true,
"showFilterInHeader": true
},
"body": [
{
"type": "selector",
"props": {
"type": "SEGMENT",
"prompt": "Status",
"options": ["All", "Available", "Reserved"],
"onSelect": "onStatusChanged"
}
},
{
"type": "repeater",
"props": {
"dataKey": "items",
"key": "itemNo",
"template": "CARD"
}
}
],
"contract": {
"initialAction": "loadInventory",
"actions": [
{
"id": "loadInventory",
"type": "api",
"method": "GetInventory",
"params": []
},
{
"id": "onStatusChanged",
"type": "filter",
"endpoint": "GetInventory",
"params": ["StatusFilter", "LocationFilter"]
}
],
"filters": [
{
"id": "StatusFilter",
"label": "Status",
"mode": "SEGMENT",
"options": ["All", "Available", "Reserved"],
"defaultValue": "All"
},
{
"id": "LocationFilter",
"label": "Location",
"mode": "DROPDOWN",
"optionsKey": "locations",
"labelKey": "name",
"valueField": "code"
}
]
}
}

Flow:

  1. Page loads -- loadInventory fetches all inventory items and a list of locations.
  2. The StatusFilter renders as a segmented control with "All", "Available", "Reserved".
  3. The LocationFilter renders as a dropdown populated from the locations array in the response data.
  4. When either filter changes, onStatusChanged calls GetInventory with both filter values, and the repeater updates.