Skip to content

Filtering ​

Filtering is configured per-column via the filterable field on a ColumnDefinition. When showFilterRow is true, an input row is rendered below the column headers. The grid creates the filter state and filters the records itself. Bind v-model:filterState to hold that state outside the grid; the records are still filtered locally unless one of the columns in the filter state declares key: filterExternal.

Column filter configuration ​

The filterable field accepts either a boolean or a FilterConfig object:

typescript
type Filterable = boolean | FilterConfig;

interface FilterConfig {
  fieldType?: 'string' | 'number' | 'boolean' | 'date'; // determines input widget; default: 'string'
  choices?: Array<{ id: any; text: string; icon?: string }>; // renders a multi-select instead of free-text input
  key?: string | typeof filterExternal;  // record property to compare against; default: column's fieldName
  placeholder?: string;                  // input placeholder text
}

The control rendered in the filter row follows from the resolved config: a column with choices gets a clearable multi-select whatever its fieldType, fieldType: 'date' gets a clearable date input, fieldType: 'boolean' gets a checkbox that also accepts the null state and uses placeholder as its label, and everything else gets a text input — a numeric one for fieldType: 'number'. Where no placeholder is given, the select, date and text inputs use Filter <label>.... Columns that are not filterable leave their filter cell empty.

Setting filterable: true uses the default config (fieldType: 'string').

Filtering is opt-in per column, and createColumn() does not set filterable: a column without filterable, with filterable: false, or with a filterable object carrying none of fieldType, choices, key or placeholder is not filterable — it gets no field in the filter state and no control in the filter row. A field in filterState that does not correspond to a filterable column stays in the state and logs a [df-grid] console warning.

filterExternal ​

Setting key: filterExternal signals that this column is filtered externally (e.g. server-side). As soon as such a column's field is part of the filter state's value — whether or not it currently holds a value — the grid stops filtering locally altogether, including the columns that would filter normally, and only emits update:filterState and filter, so the application can fetch already-filtered data.

typescript
import { filterExternal } from '@dynamicforms/vue-grid';

createColumn('title', 'Title', 'plain', { filterable: { key: filterExternal } })

A field whose access is 'disabled' is not part of the value, so while every external column's field is disabled the grid filters locally again.

Local filtering ​

A record is kept when it satisfies every active filter. A filter whose value is null, undefined or an empty string is inactive, and so is a multi-select whose value is an empty array. The comparison depends on fieldType:

fieldTypeSingle valueMulti-select (choices)
'string'case-insensitive substring match; a null/undefined record value never matchescase-insensitive equality of the whole value against any chosen value
'number'recordValue === Number(filterValue)equality against any chosen value, each converted with Number()
'boolean'strict equality against the filter valuenot supported — the record value is compared against the array itself, which never matches
'date'strict equality against the raw filter valuestrict equality against any chosen value

The record property compared is FilterConfig.key when set, otherwise the column's fieldName.

FilterState ​

typescript
type FilterState = Group<Record<string, Field<any>>>; // Group and Field from @dynamicforms/vue-forms

The group holds one Field per filterable column, keyed by the column's fieldName; the inputs in the filter row write straight into those fields. getFilterConfig() and defaultColumnFilterConfig are exported as well, for code that needs to resolve a Filterable value the same way the grid does.

Filter state is a reactive form-state object created by createFilterState(). You normally let the grid manage it, but can initialise with pre-set values:

typescript
function createFilterState(
  columns: ColumnDefinition[],
  initialValues?: Record<string, any>,
): FilterState
typescript
import { createFilterState } from '@dynamicforms/vue-grid';

const filterState = ref(createFilterState(columns, { title: 'Beatles' }));
vue
<df-grid
  v-model:filterState="filterState"
  :columns="columns"
  :records="records"
  key-field="id"
  :show-filter-row="true"
/>

GridFilterEvent ​

Emitted as @filter on every change of the filter state's value, immediately after update:filterState: a filter value edited, and a filter field's access switched where that changes what is sent. The grid neither debounces nor batches these events, and nothing is emitted before the first change:

typescript
interface GridFilterEvent {
  filterState: FilterState;             // full reactive state object
  filterValues: Record<string, any>;    // plain key→value map for easy use
}

Use filterValues for server-side filtering — it maps each filterable column's fieldName to the current input value. Every filterable column is present; one whose filter is empty carries null. A filter field whose access is 'disabled' is left out, and a 'disabled-null' one carries null whatever it holds, so neither filters; with every filter field left out, filterValues is {}. A field's visibility changes none of this: it only decides how its input is drawn. FilterConfig.key does not appear here; it only selects the record property used by local filtering.

Example: server-side filtering ​

typescript
async function onFilter({ filterValues }: GridFilterEvent) {
  records.value = await api.fetchRecords({ filters: filterValues });
}
vue
<df-grid
  :columns="columns"
  :records="records"
  key-field="id"
  :show-filter-row="true"
  @filter="onFilter"
/>

Status bar ​

Setting showStatusBar to true displays a bar below the filter row showing the number of active filters — every filter value that is not null, undefined or an empty string, so an emptied multi-select still counts. A filter field that is 'disabled' or 'disabled-null' does not count.

The bar also shows the record count:

ConditionText
recordCount prop with total{matching} of {total} records
recordCount prop without total{matching} records
local filtering{shownCount} of {loadedCount} records
a column uses filterExternal{loadedCount} records

Override the content with the #statusBar slot, which receives filterState, view (the current GridViewState) and recordCount as slot props. While selection mode is active the same bar is shown regardless of showStatusBar and carries the selection controls instead; see Selection.

Released under the MIT License.