EditingPlugin
Editing Plugin for tbw-grid
Enables inline cell editing in the grid. Provides built-in editors for common data types and supports custom editor functions for specialized input scenarios.
Why Opt-In?
Section titled “Why Opt-In?”Editing is delivered as a plugin rather than built into the core grid:
- Smaller bundle — Apps that only display data don’t pay for editing code
- Clear intent — Explicit plugin registration makes editing capability obvious
- Runtime validation — Using
editable: truewithout the plugin throws a helpful error
Installation
Section titled “Installation”import { EditingPlugin } from '@toolbox-web/grid/plugins/editing';Edit Triggers
Section titled “Edit Triggers”Configure how editing is triggered with the editOn option:
| Value | Behavior |
|---|---|
'click' | Single click enters edit mode (default) |
'dblclick' | Double-click enters edit mode |
Keyboard Shortcuts
Section titled “Keyboard Shortcuts”| Key | Action |
|---|---|
Enter | Commit edit and move down |
Tab | Commit edit and move right |
Escape | Cancel edit, restore original value |
Arrow Keys | Navigate between cells (when not editing) |
| Option | Type | Description |
|---|---|---|
mode? | row | grid | Editing mode that determines how many rows are editable at once. |
dirtyTracking? | boolean | Enable per-row dirty tracking against deep-cloned baselines. |
editOn? | false | click | dblclick | manual | Controls when editing is triggered (only applies to mode: 'row'). - ‘click’: Edit on single click (default) - ‘dblclick’: Edit on double click - ‘manual’: Only via programmatic API (beginEdit) - false: Disable editing entirely |
onBeforeEditClose? | (event: MouseEvent | KeyboardEvent) => boolean | Callback invoked before a row edit session closes. |
focusTrap? | boolean | When true, prevents focus from leaving the grid (or its registered external focus containers) while a row is in edit mode. |
Examples
Section titled “Examples”Basic editing with double-click trigger
Section titled “Basic editing with double-click trigger”grid.gridConfig = { columns: [ { field: 'name', editable: true }, { field: 'price', type: 'number', editable: true }, { field: 'active', type: 'boolean', editable: true }, ], plugins: [new EditingPlugin({ editOn: 'dblclick' })],};
grid.on('cell-commit', ({ field, oldValue, newValue }) => { console.log(`${field}: ${oldValue} → ${newValue}`);});Custom editor function
Section titled “Custom editor function”columns: [ { field: 'status', editable: true, editor: (ctx) => { const select = document.createElement('select'); ['pending', 'active', 'completed'].forEach(opt => { const option = document.createElement('option'); option.value = opt; option.textContent = opt; option.selected = ctx.value === opt; select.appendChild(option); }); select.addEventListener('change', () => ctx.commit(select.value)); return select; }, },]See Also
Section titled “See Also”EditingConfigfor configuration optionsEditorContextfor custom editor contextEditingConfigfor interactive examples in the docs site
Extends BaseGridPlugin
Inherited methods like
attach(),detach(),afterRender(), etc. are documented in the base class.
Events
Section titled “Events”| Event | Description | Triggered By |
|---|---|---|
changed-rows-reset | Emitted when tracking is reset (unless silent) | resetChangedRows() |
cell-commit | Emitted when the cell value is committed (on blur or Enter) | beginCellEdit(), beginBulkEdit() |
row-commit | Emitted after the row edit is committed | beginBulkEdit(), commitActiveRowEdit() |
Accessors
Section titled “Accessors”changedRows
Section titled “changedRows”Get all rows that have been modified. Uses ID-based lookup for stability when rows are reordered.
readonly changedRows: T[]changedRowIds
Section titled “changedRowIds”Get IDs of all modified rows.
readonly changedRowIds: string[]activeEditRow
Section titled “activeEditRow”Get the currently active edit row index, or -1 if not editing.
readonly activeEditRow: numberactiveEditCol
Section titled “activeEditCol”Get the currently active edit column index, or -1 if not editing.
readonly activeEditCol: numberWhether any row in the grid is dirty.
readonly dirty: booleanpristine
Section titled “pristine”Whether all rows are pristine.
readonly pristine: booleandirtyRowIds
Section titled “dirtyRowIds”Get IDs of all dirty rows.
readonly dirtyRowIds: string[]Methods
Section titled “Methods”isRowEditing()
Section titled “isRowEditing()”Check if a specific row is currently being edited.
isRowEditing(rowIndex: number): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number |
isCellEditing()
Section titled “isCellEditing()”Check if a specific cell is currently being edited.
isCellEditing(rowIndex: number, colIndex: number): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number | |
colIndex | number |
isRowChanged()
Section titled “isRowChanged()”Check if a specific row has been modified.
isRowChanged(rowIndex: number): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number | Row index to check (will be converted to ID internally) |
isRowChangedById()
Section titled “isRowChangedById()”Check if a row with the given ID has been modified.
isRowChangedById(rowId: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | Row ID to check |
isDirty()
Section titled “isDirty()”Check if a row differs from its baseline. Requires dirtyTracking: true.
isDirty(rowId: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
isPristine()
Section titled “isPristine()”Inverse of isDirty.
isPristine(rowId: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
markAsPristine()
Section titled “markAsPristine()”Re-snapshot baseline from current data (call after a successful save).
markAsPristine(rowId: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
markAsNew()
Section titled “markAsNew()”Mark a row as new (auto-called by insertRow() when dirty tracking is on).
markAsNew(rowId: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
markAsDirty()
Section titled “markAsDirty()”Mark a row as dirty after an external mutation that bypassed the editing pipeline.
markAsDirty(rowId: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
markAllPristine()
Section titled “markAllPristine()”Mark all tracked rows as pristine (call after a batch save).
markAllPristine(): voidgetOriginalRow()
Section titled “getOriginalRow()”Get a deep clone of the original (baseline) row data. Returns undefined for new rows.
getOriginalRow(rowId: string): T | undefinedParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
hasBaseline()
Section titled “hasBaseline()”Lightweight check for whether a baseline exists (no cloning).
hasBaseline(rowId: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
getDirtyRows()
Section titled “getDirtyRows()”Get all dirty rows with their original and current data.
getDirtyRows(): DirtyRowEntry<T>[]revertRow()
Section titled “revertRow()”Revert a row to its baseline values (mutates the current row in-place). Triggers a re-render.
revertRow(rowId: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | Row ID (from getRowId) |
revertAll()
Section titled “revertAll()”Revert all dirty rows to their baseline values and re-render.
revertAll(): voidsetInvalid()
Section titled “setInvalid()”Mark a cell as invalid with an optional validation message.
Invalid cells are marked with a data-invalid attribute for styling.
setInvalid(rowId: string, field: string, message: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | The row ID (from getRowId) |
field | string | The field name |
message | string | Optional validation message (for tooltips or display) |
Example
Section titled “Example”// In cell-commit handler:grid.on('cell-commit', (detail, e) => { if (detail.field === 'email' && !isValidEmail(detail.value)) { detail.setInvalid('Invalid email format'); }});
// Or programmatically:editingPlugin.setInvalid('row-123', 'email', 'Invalid email format');clearInvalid()
Section titled “clearInvalid()”Clear the invalid state for a specific cell.
clearInvalid(rowId: string, field: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | |
field | string |
clearRowInvalid()
Section titled “clearRowInvalid()”Clear all invalid cells for a specific row.
clearRowInvalid(rowId: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
clearAllInvalid()
Section titled “clearAllInvalid()”Clear all invalid cell states across all rows.
clearAllInvalid(): voidisCellInvalid()
Section titled “isCellInvalid()”Check if a specific cell is marked as invalid.
isCellInvalid(rowId: string, field: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | |
field | string |
getInvalidMessage()
Section titled “getInvalidMessage()”Get the validation message for an invalid cell.
getInvalidMessage(rowId: string, field: string): string | undefinedParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string | |
field | string |
hasInvalidCells()
Section titled “hasInvalidCells()”Check if a row has any invalid cells.
hasInvalidCells(rowId: string): booleanParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
getInvalidFields()
Section titled “getInvalidFields()”Get all invalid fields for a row.
getInvalidFields(rowId: string): Map<string, string>Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowId | string |
resetChangedRows()
Section titled “resetChangedRows()”Reset all change tracking.
resetChangedRows(silent: boolean): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
silent | boolean | If true, suppresses the changed-rows-reset event |
Events
Section titled “Events”| Event | Description |
|---|---|
changed-rows-reset | Emitted when tracking is reset (unless silent) |
beginCellEdit()
Section titled “beginCellEdit()”Programmatically begin editing a cell.
beginCellEdit(rowIndex: number, field: string): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number | Index of the row to edit |
field | string | Field name of the column to edit |
Events
Section titled “Events”| Event | Description |
|---|---|
cell-commit | Emitted when the cell value is committed (on blur or Enter) |
beginBulkEdit()
Section titled “beginBulkEdit()”Programmatically begin editing all editable cells in a row.
beginBulkEdit(rowIndex: number): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number | Index of the row to edit |
Events
Section titled “Events”| Event | Description |
|---|---|
cell-commit | Emitted for each cell value that is committed |
row-commit | Emitted when focus leaves the row |
commitActiveRowEdit()
Section titled “commitActiveRowEdit()”Commit the currently active row edit.
commitActiveRowEdit(): voidEvents
Section titled “Events”| Event | Description |
|---|---|
row-commit | Emitted after the row edit is committed |
cancelActiveRowEdit()
Section titled “cancelActiveRowEdit()”Cancel the currently active row edit.
cancelActiveRowEdit(): void