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.
| Property | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier for this filter. Used as a parameter key in action params arrays and in data bindings. |
label | string | required | Display label shown next to the filter control. |
mode | FilterMode | "DROPDOWN" | The filter input mode. Determines how the filter is rendered. See FilterMode below. |
variant | SelectorType | "DROPDOWN" | Visual variant for the filter control. Values: "DROPDOWN" or "SEGMENT". Controls rendering style independently of behavior. |
options | string[] | [] | Static list of option strings. Use this for filters with a fixed set of choices known at page-authoring time. |
optionsKey | string? | null | Data 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. |
labelKey | string | "label" | When using optionsKey, the field name within each option object to use as the display label. |
valueField | string? | null | When 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. |
defaultValue | string? | null | The initial selected value when the page loads. When null, no option is pre-selected. |
segmentKey | string? | null | A data context key whose value is overridden when a segment option is selected. Used to drive segment-based navigation or data switching. |
segmentMapping | object | {} | 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.
| Value | Description |
|---|---|
DROPDOWN | A dropdown picker. The user taps to open a list and selects one option. Best for filters with many options (5+). |
SEGMENT | A segmented control (horizontal row of buttons). The user taps one segment to select it. Best for filters with 2--4 options. |
LOOKUP | Opens 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). |
DATE | A 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):
- If
optionsis non-empty, use it directly (static mode). - Otherwise, if
optionsKeyis set, look up that key in the page data to get an array of objects. - For each object, extract the display label using
labelKey(defaults to"label"). - If the object does not contain the
labelKeyfield, 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:
- A filter definition in
contract.filters-- defines the filter's options and behavior. - A filter action in
contract.actions-- defines the API endpoint to call when the filter changes. - 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:
- Page loads --
loadInventoryfetches all inventory items and a list of locations. - The
StatusFilterrenders as a segmented control with "All", "Available", "Reserved". - The
LocationFilterrenders as a dropdown populated from thelocationsarray in the response data. - When either filter changes,
onStatusChangedcallsGetInventorywith both filter values, and the repeater updates.