EditingPlugin
EditingPlugin manages the cell editing lifecycle, editor registration, and popup coordination.
The EditingPlugin integrates ZenGrid’s cell editing functionality with the reactive store system, managing the editing lifecycle and coordinating with editors.
Overview
EditingPlugin runs at phase 45 and provides:
- Cell editing lifecycle management
- Editor registration and coordination
- Popup positioning for dropdowns and date pickers
- Keyboard integration (Enter/Escape/Tab)
- Integration with SelectionPlugin for edit-on-select
EditingPlugin depends on CorePlugin and coordinates with SelectionPlugin when available.
Creation
Create the EditingPlugin using the factory function:
import { createEditingPlugin } from '@zengrid/core';
const editingPlugin = createEditingPlugin();grid.usePlugin(editingPlugin);Editor Registration
Register built-in and custom editors:
import { TextEditor, NumberEditor, DropdownEditor, DateEditor, CheckboxEditor} from '@zengrid/core';
const grid = createGrid(container, { columns: [ { id: 'name', field: 'name', editor: TextEditor }, { id: 'age', field: 'age', editor: NumberEditor }, { id: 'status', field: 'status', editor: DropdownEditor }, { id: 'date', field: 'date', editor: DateEditor }, { id: 'active', field: 'active', editor: CheckboxEditor } ]});
grid.usePlugin(createEditingPlugin());Built-in Editors
| Editor | Purpose | Features |
|---|---|---|
| TextEditor | Plain text input | Validation, masking |
| NumberEditor | Numeric input | Min/max, decimals |
| DropdownEditor | Select from list | Search, custom options |
| DateEditor | Date picker | Calendar, formats |
| DateTimeEditor | Date and time | Combined picker |
| TimeEditor | Time picker | 12/24 hour |
| CheckboxEditor | Boolean toggle | Tri-state support |
| SelectEditor | Multi-select | Chips, tags |
Editing Lifecycle
EditingPlugin manages the complete editing lifecycle:
// 1. Start editinggrid.api.editing.startEditing(row, col);
// 2. Editor opens and receives focus// - EditingPlugin creates editor instance// - Positions popup if needed// - Attaches event listeners
// 3. User edits value// - Editor validates input// - Provides visual feedback
// 4. Commit or cancelgrid.api.editing.commitEdit(); // Save changesgrid.api.editing.cancelEdit(); // Discard changes
// 5. Editor closes// - Cleanup event listeners// - Destroy editor instanceEditingPlugin automatically handles keyboard shortcuts: Enter commits, Escape cancels, Tab moves to next cell.
Reactive State
EditingPlugin creates these reactive signals:
// Active editorstore.get('editing.active') // { row: number, col: number, editor: Editor } | nullstore.set('editing.active', state)
// Editing statestore.get('editing.isEditing') // Boolean: currently editingstore.get('editing.editValue') // Current value being editedstore.get('editing.isDirty') // Boolean: value changedAPI Methods
EditingPlugin registers these methods on grid.api.editing:
// Start editinggrid.api.editing.startEditing(row, col);
// Commit changesgrid.api.editing.commitEdit();
// Cancel editinggrid.api.editing.cancelEdit();
// Check if editingconst isEditing = grid.api.editing.isEditing();
// Get active editorconst editor = grid.api.editing.getActiveEditor();
// Move to next editable cellgrid.api.editing.moveToNextEditableCell();
// Move to previous editable cellgrid.api.editing.moveToPreviousEditableCell();Keyboard Integration
EditingPlugin handles keyboard events:
// Enter: Start editing or commit editgrid.on('editing:keydown:enter', () => { if (!isEditing) { grid.api.editing.startEditing(row, col); } else { grid.api.editing.commitEdit(); }});
// Escape: Cancel editinggrid.on('editing:keydown:escape', () => { grid.api.editing.cancelEdit();});
// Tab: Move to next cell and start editinggrid.on('editing:keydown:tab', (event) => { grid.api.editing.commitEdit(); grid.api.editing.moveToNextEditableCell(); event.preventDefault();});
// Shift+Tab: Move to previous cellgrid.on('editing:keydown:shifttab', (event) => { grid.api.editing.commitEdit(); grid.api.editing.moveToPreviousEditableCell(); event.preventDefault();});Popup Coordination
EditingPlugin manages popup positioning for dropdown and date editors:
// Dropdown editor with popupconst grid = createGrid(container, { columns: [ { id: 'status', field: 'status', editor: DropdownEditor, editorParams: { options: ['Active', 'Inactive', 'Pending'], popupPosition: 'auto' // 'auto' | 'top' | 'bottom' } } ]});
// EditingPlugin automatically positions popup// - Detects available space above/below// - Adjusts position to stay in viewport// - Handles scroll eventsEditingPlugin uses PopupPositioner from datetime-core for intelligent popup placement.
Edit-on-Select
Integrate with SelectionPlugin for edit-on-select:
const grid = createGrid(container, { editing: { editOnSelect: true, // Start editing when cell selected editOnDoubleClick: false }});
grid.usePlugin(createSelectionPlugin());grid.usePlugin(createEditingPlugin());
// Single click selects and starts editinggrid.api.selection.selectCell(5, 2);// EditingPlugin automatically starts editingEvents
EditingPlugin emits events for editing lifecycle:
grid.on('editing:start', (event) => { console.log('Editing started:', event.row, event.col);});
grid.on('editing:commit', (event) => { console.log('Edit committed:', event.oldValue, event.newValue);});
grid.on('editing:cancel', (event) => { console.log('Edit cancelled:', event.row, event.col);});
grid.on('editing:validation', (event) => { console.log('Validation:', event.valid, event.message);});Custom Editors
Create custom editors that integrate with EditingPlugin:
import { IEditor } from '@zengrid/core';
class CustomEditor implements IEditor { private element: HTMLElement; private value: any;
init(params: EditorParams): void { this.element = document.createElement('input'); this.element.value = params.value; params.container.appendChild(this.element); }
getValue(): any { return this.element.value; }
destroy(): void { this.element.remove(); }
focus(): void { this.element.focus(); }}
// Use custom editorconst grid = createGrid(container, { columns: [ { id: 'custom', field: 'custom', editor: CustomEditor } ]});Validation
EditingPlugin supports editor validation:
const grid = createGrid(container, { columns: [ { id: 'email', field: 'email', editor: TextEditor, editorParams: { validate: (value: string) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(value) || 'Invalid email address'; } } } ]});
// Validation runs on commitgrid.on('editing:validation', (event) => { if (!event.valid) { console.error('Validation failed:', event.message); }});EditingPlugin prevents commit if validation fails and displays error message.
Integration with Store
EditingPlugin integrates seamlessly with the reactive store:
// Watch editing changesstore.effect('logEditingChanges', () => { const isEditing = store.get('editing.isEditing'); const editValue = store.get('editing.editValue'); console.log('Editing:', isEditing, editValue);}, 'MyComponent', 100);
// Computed from editing statestore.computed('editing.canCommit', () => { const isDirty = store.get('editing.isDirty'); const isValid = store.get('editing.isValid'); return isDirty && isValid;}, 'MyComponent', 100);Performance
EditingPlugin optimizes editing operations:
- Lazy editor creation: Editors created only when needed
- Editor pooling: Reuses editor instances
- Event delegation: Single event listener per grid
- Popup caching: Cached popup calculations