Filter builder โ
A universal, inline OData filter builder. controlMonoFilterBuilder owns the filter; <mono-filter-builder :control-filter-builder.prop="โฆ"> renders it as nested rule rows and writes edits straight back.
Control โ
controlMonoFilterBuilder owns the filter tree; bind it with :control-filter-builder and read it back as an OData $filter string whenever it notifies.
It also owns the element's own props. Declare them in the controller's props block and <mono-filter-builder> needs nothing but the controller binding โ the same arrangement as controlMonoTable({ props }), minus the per-element nesting, since this family has a single element.
ts
const filter = controlMonoFilterBuilder({
fields,
props: { size: 'sm', width: '100%', maxHeight: 260 },
})
filter.props() // { size: 'sm', width: '100%', maxHeight: 260 }
filter.setProps({ size: 'lg' }) // merges, notifies, the element re-appliesprops() returns one object with a stable identity, so a controller can be handed around and stay in sync. setProps is a merge โ keys you omit keep their current value. A grid-owned builder takes the same block: controlMonoTable({ filterBuilder: { props: โฆ } }).
Setting props on the element still works
Writing size / width / max-height directly on <mono-filter-builder> is still supported. Where both declare the same key, the controller wins; keys the controller never mentions are left to the template.
Basic โ
Reading the filter โ
ts
const filter = controlMonoFilterBuilder({ fields, filter: ['Name', 'contains', 'Andy'] })
filter.original({ type: 'array' }) // the filter as first supplied โ never changes
filter.changed({ type: 'array' }) // as currently edited; a devextreme expr โ feed to a DataSource
filter.changed({ type: 'string' }) // an OData $filter โ "contains(Name,'Andy')"
filter.changed() // omit `type` to get back the shape you passed insubscribe(cb) fires on every edit; the element also emits mno-change (with array and string in the detail), plus mno-apply / mno-clear from the action row.
filter takes either shape โ
There is no filterType flag โ a string is parsed, an array is normalised, decided by typeof. Input and output shapes are independent, so you can load a string and read back an array.
Parsing covers the subset this builder emits
The string parser handles parentheses, and / or / not, the six comparisons, contains / startswith / endswith, in (โฆ), null, and quoted / numeric / boolean literals. Anything else โ a lambda like Job/any(d: d/X eq 1), arithmetic, other functions โ warns once and yields an empty builder rather than a filter that silently means something different. Array input has no such limit.
Fields โ
fields is the source of truth for the field dropdown โ dataType decides which operators and value editor a column gets, values renders a select instead of free text, and a dotted field maps a nav column (Job.Name โ Job/Name). Pass dataGrid: table instead (or as well) to derive fields from a table's props.th; explicit fields win.
Operators โ
Only OData-expressible operators are offered, filtered by dataType โ pick a field type in the demo to see each set. Group operators are and / or / notAnd / notOr (the last two wrap the group in not (โฆ)). in expands to an OR of equalities, between to ge โฆ and le โฆ, and isblank / isnotblank to eq null / ne null. Values are quoted properly โ O'Brien serialises as 'O''Brien', numbers and booleans stay bare.
Localisation โ
Every user-facing string is overridable through texts; anything omitted keeps its English default.
ts
controlMonoFilterBuilder({
fields,
texts: {
matchPrefix: 'Cocokkan', matchSuffix: 'dari aturan berikut:',
and: 'semua', or: 'apapun',
contains: 'mengandung', eq: 'adalah sama dengan', isblank: 'diatur',
addRule: 'Peraturan Baru', apply: 'Pencarian', clear: 'Buang',
},
})Apply / Clear โ
The action row renders above the rules. It's on by default; pass actions: false when the surrounding modal supplies its own buttons and you'd rather read changed() yourself.
Custom serializer โ
type: 'string' uses a built-in serializer. To route it through your own โ e.g. dxFilterToString from mono-utils โ pass toODataString; it must be synchronous, and it only affects the string form.
ts
const { dxFilterToString } = useMonoUtility()
controlMonoFilterBuilder({ fields, toODataString: (f) => dxFilterToString({ filter: f }) })CSS Variables โ
Themed through --mono-filter-* (read via private --_mono-filter-* resolvers, so they inherit and pierce the shadow boundary): -primary, -accent, -text, -muted, -border, -surface, -danger, -indent (nested-group indent).
Types โ
controlMonoFilterBuilder is also exported as monoFilterBuilder, and :control-filter-builder is also accepted as :data-filter โ the older spellings still work.
Import
import { MonoFilterBuilderProps } from 'mono-helper'| Prop | Value | Default | Description |
|---|---|---|---|
dataFilter | MonoFilterController | โ | The controller, bound with `:data-filter.prop` / `:dataFilter`. |
controlFilterBuilder | MonoFilterController | โ | Renamed โ `:control-filter-builder` / `:controlFilterBuilder` alias `dataFilter`. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | โ | Visual size of the inner controls (default `sm`). |
width | string | number | โ | Fixed builder width (CSS length or px number). |
height | string | number | โ | Fixed builder height โ when set, the rules scroll between the pinned Apply/Clear row and the Add rule/group row. |
minWidth | string | number | โ | โ |
maxWidth | string | number | โ | โ |
minHeight | string | number | โ | โ |
maxHeight | string | number | โ | Caps the builder height so a long rule list scrolls instead of growing. |