api reference
Filtering, sorting and quick filter
grid.filters and the condition tree, grid.sort, facets, quick filter modes, and the filter grammar.
API reference › Filtering, sorting and quick filter
grid.filters
| Method | Returns | Description |
|---|---|---|
| get() | FilterSet | The whole condition tree. |
| set(filters) | void | Replace it. null clears everything. |
| quick(text, opts?) | void | The quick filter, applied across every column. |
| clear() | void |
grid.sort
| Method | Returns | Description |
|---|---|---|
| get() | SortEntry[] | { col, dir, nullsFirst? }, in priority order. |
| set(entries) | void | Multi-sort by passing several entries. |
| clear() | void |
grid.facets
A distribution chart in each column heading, which is also a filter control. Clicking a bar filters to that bucket; dragging across bars on an ordered column filters to the range. As filters are applied, the other columns' charts recount, so a dataset can be explored by clicking through headings rather than opening a dialog.
Off by default. The band roughly doubles the header's height.
facets: { enabled: true } // grid-wide
// per column, layered over the grid's settings
{ field: 'price', type: 'number', facet: { strategy: 'quantile', buckets: 16 } }
{ field: 'notes', facet: false } // opt one column out
| Method | Returns | Description |
|---|---|---|
| get(colId) | object | null | { bounds, counts, unfiltered, stale, suppressed }. Schedules the computation if it has not run; redraw on facet:computed rather than awaiting. |
| suppression(colId) | string | null | Why there is no chart: type, cardinality, rows, streaming, no-provider, disabled. Null when there is one. |
| config(colId?) | object | The resolved settings, column layered over grid. |
| select(colId, from, to?, opts?) | boolean | Filter to a bucket, or to the range from-to. opts.additive adds to a categorical set. Selecting what is already selected clears it. |
| clear(colId) | boolean | Remove only this column's filter, leaving every other filter in place. |
| selected(colId) | number[] | Which buckets the column's own filter currently covers. |
| toggle(colId, open?) | boolean | Expand or collapse the chart. Rides in a saved view. |
| isExpanded(colId) | boolean | |
| refresh(opts?) | void | Recount every chart. immediate skips the debounce. |
| expanded() | string[] | Every expanded column. |
A column is never counted against its own filter. Every other active filter applies; that column's own conditions are pruned out. Without this, clicking a bucket would collapse the chart to that single bar, leaving no way to see what was excluded or to widen the selection.
The filters are ordinary filters. They go through filters.set, so they undo, ride in saved views, and appear in whatever filter UI you already have. A drag emits a between range rather than a set of bucket indices, so it still means something after the data is replaced and the edges move.
| Option | Default | Description |
|---|---|---|
| enabled | false | Grid-wide, or per column. |
| collapsed | true | Start as a one-line density strip that opens on click. |
| height | 28 | Band height in pixels. |
| buckets | 20 | Numeric and date columns. |
| strategy | 'equal' | equal, quantile or log. Equal width looks wrong on skewed data. |
| granularity | auto | hour … year. Chosen from the span when omitted. |
| order | 'count' | count or alpha, for categorical columns. |
| cardinalityLimit | 50 | Distinct values above which a text column has no readable chart. |
| aboveLimit | 'suppress' | suppress, or topN for a top list with an aggregated remainder. |
| rowCeiling | 2000000 | Rows above which charts are suppressed. |
| debounce | 120 | Milliseconds a filter change waits before charts recount. |
| whilePaused | true | Whether a paused stream re-enables charts. |
| provider | , | Async bucket counts for a paged or remote source. Without one, charts are suppressed silently. |
| format | , | (bucket, count, unfiltered) => string for tooltips and accessible names. |
Live streams suppress charts. Buckets that move under the pointer are worse than no chart, the control lies about what clicking it will do. Filters already made stay applied, because they are ordinary filters. Pausing the stream brings the charts back; set whilePaused: false if you would rather it did not.
Server-side sources need a provider. It receives the column, the current filter state with that column's own conditions removed, and the bucketing settings, and returns counts. Results are cached against the filter state, but this is still one query per column per filter change, a grid with eight faceted columns will ask eight questions every time a filter moves, and the backend has to be able to absorb that.
Charts are keyboard operable: focus enters from the header, arrows move between buckets, Enter toggles, Shift with arrows extends a range on ordered columns, Escape clears. Each bucket carries its range and count as an accessible name, and the chart as a whole carries a one-sentence description of the distribution's shape, which is the part bar-by-bar labels cannot convey.
Quick filter modes
One box, four ways to match. The mode persists until changed, so a host sets it once and goes on passing text alone.
grid.filters.quick('acme london', { mode: 'words' });
grid.filters.quickState(); // { text: 'acme london', mode: 'words' }
| Mode | Matches | Example |
|---|---|---|
| contains | The text appears somewhere in the row. The default. | cir finds CIR-100 |
| words | Every term appears, in any order and any column. | acme london finds a row with one in each |
| fuzzy | The characters appear in order, not necessarily together. | crc finds CIR-200 Manchester |
| regex | A regular expression, case-insensitive. | ^CIR-[12] |
Matching is against one cached text blob per row, built from the columns the viewer is permitted to see. Hidden and unreadable columns are excluded, so the row count cannot become an oracle for a value behind them.
An unfinished regular expression (foo( on the
way to foo(bar)) falls back to a literal search rather than matching nothing, so the
grid does not blank on every open bracket. fuzzy does not reorder rows: ranking
results would fight the sort the user chose.
Filter grammar
The condition tree is a published wire protocol, not an internal shape. It serialises into saved state and travels to a remote source unchanged.
grid.filters.set({
op: 'and',
conditions: [
{ col: 'region', op: 'eq', value: 'EMEA' },
{ col: 'capacity', op: 'between', value: [100, 500], bounds: '[)' },
{ op: 'not', conditions: [
{ col: 'status', op: 'in', value: ['closed'] },
] },
],
});
| Group | Operators |
|---|---|
| Equality | eq, ne |
| Ordering | lt, lte, gt, gte |
| Ranges | between, notBetween, with bounds of '[]', '[)', '(]' or '()' |
| Sets | in, notIn |
| Text | contains, notContains, startsWith, endsWith, matches |
| Blankness | blank, notBlank |
| Multi-value | containsAny, containsAll, containsNone, for cells holding an array of ids |
| Grouping | and, or, not |
One filter, not two. A condition set from a header popup, from the tool panel, or through grid.filters.set() all merge into the same tree. Reading grid.filters.get() always gives the whole truth.