# FilteringPlugin

> _Since v0.1.1_

Filtering Plugin for tbw-grid

Adds column header filters with text search, dropdown options, and custom filter panels.
Supports both **local filtering** for small datasets and **async handlers** for server-side
filtering on large datasets.

## Installation

```ts
import { FilteringPlugin } from '@toolbox-web/grid/plugins/filtering';
```

## Column Configuration

| Property | Type | Description |
|----------|------|-------------|
| `filterable` | `boolean` | Enable filtering for this column |
| `filterType` | `'text' \| 'select' \| 'number' \| 'date'` | Filter UI type |
| `filterOptions` | `unknown[]` | Predefined options for select filters |

## CSS Custom Properties

| Property | Default | Description |
|----------|---------|-------------|
| `--tbw-filter-panel-bg` | `var(--tbw-color-panel-bg)` | Panel background |
| `--tbw-filter-panel-fg` | `var(--tbw-color-fg)` | Panel text color |
| `--tbw-filter-panel-border` | `var(--tbw-color-border)` | Panel border |
| `--tbw-filter-active-color` | `var(--tbw-color-accent)` | Active filter indicator |
| `--tbw-filter-input-bg` | `var(--tbw-color-bg)` | Input background |
| `--tbw-filter-input-focus` | `var(--tbw-color-accent)` | Input focus border |

## [Configuration Options](/grid/plugins/filtering/interfaces/filterconfig.md)

| Option | Type | Description |
| ------ | ---- | ----------- |
| `debounceMs?` | <code>number</code> | Debounce delay in milliseconds for the search input inside the default filter panel. Controls how long the panel waits after the user stops typing before re-filtering the unique values list. |
| `caseSensitive?` | <code>boolean</code> | Whether text-based filtering comparisons are case-sensitive. |
| `filterPanelRenderer?` | <code><a href="/grid/plugins/filtering/types/filterpanelrenderer/">FilterPanelRenderer</a></code> | Custom filter panel renderer that replaces the built-in panel content for **all** columns (unless you return `undefined` for specific columns to fall through to the next level). |
| `trackColumnState?` | <code>boolean</code> | Whether filter state should be included in column state persistence. |
| `valuesHandler?` | <code><a href="/grid/plugins/filtering/types/filtervalueshandler/">FilterValuesHandler</a></code> | Async handler for fetching unique filter values from a server. |
| `filterHandler?` | <code><a href="/grid/plugins/filtering/types/filterhandler/">FilterHandler</a>&lt;TRow&gt;</code> | Async handler for delegating filtering to a server. |

## Examples

### Basic Usage with Filterable Columns

```ts
import { queryGrid } from '@toolbox-web/grid';
import { FilteringPlugin } from '@toolbox-web/grid/plugins/filtering';

const grid = queryGrid('tbw-grid');
grid.gridConfig = {
  columns: [
    { field: 'name', header: 'Name', filterable: true },
    { field: 'status', header: 'Status', filterable: true, filterType: 'select' },
    { field: 'email', header: 'Email', filterable: true },
  ],
  plugins: [new FilteringPlugin({ debounceMs: 300 })],
};
grid.rows = data;
```

### Column Formatters in Filter Panel

```ts
When a column defines a `format` function, the built-in set filter panel
displays formatted labels instead of raw values. Search within the panel
also matches against the formatted text.
```ts
grid.gridConfig = {
  columns: [
    {
      field: 'price',
      filterable: true,
      format: (value) => `$${Number(value).toFixed(2)}`,
      // Filter checkboxes show "$9.99" instead of "9.99"
    },
  ],
  plugins: [new FilteringPlugin()],
};
```
```

### Server-Side Filtering with Async Handlers

```ts
new FilteringPlugin({
  // Fetch unique values from server for filter dropdown
  valuesHandler: async (field, column) => {
    const response = await fetch(`/api/distinct-values?field=${field}`);
    return response.json();
  },
  // Apply filters on the server
  filterHandler: async (filters, currentRows) => {
    const response = await fetch('/api/data', {
      method: 'POST',
      body: JSON.stringify({ filters }),
    });
    return response.json();
  },
});
```

## See Also

- [`FilterConfig`](/grid/plugins/filtering/interfaces/filterconfig.md) for all configuration options
- [`FilterModel`](/grid/plugins/filtering/interfaces/filtermodel.md) for filter data structure
- [`FilterPanelParams`](/grid/plugins/filtering/interfaces/filterpanelparams.md) for custom panel renderer parameters

> **Extends** [BaseGridPlugin](/docs/grid-api-plugin-development-classes-basegridplugin--docs)
>
> Inherited methods like `attach()`, `detach()`, `afterRender()`, etc. are documented in the base class.

## Methods

### setFilter()

Set a filter on a specific field.
Pass null to remove the filter.

```ts
setFilter(field: string, filter: Omit<FilterModel, "field"> | null, options: object): void
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |
| `filter` | <code>Omit&lt;<a href="/grid/plugins/filtering/interfaces/filtermodel/">FilterModel</a>, field&gt; &#124; unknown</code> |  |
| `options` | <code>object</code> | `{ silent: true }` applies the filter without emitting `filter-change` |

***

### getFilter()

Get the current filter for a field.

```ts
getFilter(field: string): FilterModel | undefined
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |

***

### getFilters()

Get all active filters.

```ts
getFilters(): FilterModel[]
```

***

### getFilterModel()

Alias for getFilters() to match functional API naming.

```ts
getFilterModel(): FilterModel[]
```

***

### setFilterModel()

Set filters from an array (replaces all existing filters).

```ts
setFilterModel(filters: FilterModel[], options: object): void
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `filters` | <code><a href="/grid/plugins/filtering/interfaces/filtermodel/">FilterModel</a>[]</code> |  |
| `options` | <code>object</code> | `{ silent: true }` applies filters without emitting `filter-change` |

***

### clearAllFilters()

Clear all filters.

```ts
clearAllFilters(options: object): void
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `options` | <code>object</code> | `{ silent: true }` clears filters without emitting `filter-change` |

***

### clearFieldFilter()

Clear filter for a specific field.

```ts
clearFieldFilter(field: string, options: object): void
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |
| `options` | <code>object</code> | `{ silent: true }` clears filter without emitting `filter-change` |

***

### isFieldFiltered()

Check if a field has an active filter.

```ts
isFieldFiltered(field: string): boolean
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |

***

### getFilteredRowCount()

Get the count of filtered rows (from cache).

```ts
getFilteredRowCount(): number
```

***

### getActiveFilters()

Get all active filters (alias for getFilters).

```ts
getActiveFilters(): FilterModel[]
```

***

### getUniqueValues()

Get unique values for a field (for set filter dropdowns).

Prefers `sourceRows` (raw user input). When the user does not own the data
(e.g. `ServerSidePlugin` is active and `sourceRows` is empty), falls back
to the processed `rows` with placeholder/loading rows excluded so users get
filter values for whatever has been loaded so far.

When a column has `filterValue`, individual extracted values are returned.

```ts
getUniqueValues(field: string): unknown[]
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |

***

### getStaleFilters()

Get set filters whose exclusion/inclusion list no longer matches any values
in the current data, effectively selecting zero rows.

- `notIn`: stale when every current unique value is in the exclusion list (selected count = 0)
- `in`: stale when none of the included values exist in the current data

```ts
getStaleFilters(): FilterModel[]
```

***

### getBlankMode()

Get the current blank mode for a field.
- `'all'` — no blank filter active
- `'blanksOnly'` — `blank` operator active
- `'nonBlanksOnly'` — `notBlank` operator active

```ts
getBlankMode(field: string): BlankMode
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |

***

### toggleBlankFilter()

Toggle blank filter mode for a field.

Handles transitions:
- `'all'` → clears the filter entirely
- `'blanksOnly'` → sets `blank` operator, stashing any active filter in `valueTo`
- `'nonBlanksOnly'` → sets `notBlank` operator, stashing any active filter in `valueTo`

When switching back to `'all'`, the stashed filter (if any) is restored.

```ts
toggleBlankFilter(field: string, mode: BlankMode): void
```

#### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `field` | <code>string</code> |  |
| `mode` | <code><a href="/grid/plugins/filtering/types/blankmode/">BlankMode</a></code> |  |

***
