RevoGrid features an extensible plugin architecture that allows you to add custom functionality or extend existing capabilities. The plugin system provides access to all grid providers and enables you to hook into the grid's lifecycle and events.
Foundation class for creating custom plugins with access to grid functionality.
/**
* Base class for all grid plugins
*/
abstract class BasePlugin {
/** Grid element reference */
protected revogrid: HTMLRevoGridElement;
/** Plugin providers for accessing grid services */
protected providers: PluginProviders;
/**
* Create a new plugin instance
* @param revogrid - Grid element reference
* @param providers - Plugin providers
*/
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
/**
* Subscribe to grid events
* @param eventName - Event name to listen for
* @param callback - Event callback function
*/
addEventListener<K extends keyof CustomEventMap>(
eventName: K,
callback: (event: CustomEvent<CustomEventMap[K]>) => void
): void;
/**
* Watch property changes in grid stores
* @param prop - Property name to watch
* @param callback - Change callback function
* @param config - Watch configuration
*/
watch<T>(
prop: string,
callback: (newValue: T, oldValue: T) => void,
config?: WatchOptions
): void;
/**
* Remove event listener
* @param eventName - Event name to remove
*/
removeEventListener(eventName: string): void;
/**
* Emit custom event
* @param eventName - Event name
* @param detail - Event detail data
*/
emit<T>(eventName: string, detail?: T): void;
/**
* Clear all subscriptions and watchers
*/
clearSubscriptions(): void;
/**
* Destroy plugin and clean up resources
*/
destroy(): void;
}Usage Example:
import { BasePlugin, PluginProviders } from '@revolist/revogrid';
class CustomHighlightPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders) {
super(revogrid, providers);
// Listen for cell focus events
this.addEventListener('afterfocus', this.onCellFocus.bind(this));
// Watch for data changes
this.watch('source', this.onDataChange.bind(this));
}
private onCellFocus(event: CustomEvent) {
console.log('Cell focused:', event.detail);
// Add custom highlighting logic
}
private onDataChange(newData: any[], oldData: any[]) {
console.log('Data changed from', oldData.length, 'to', newData.length);
}
}
// Register plugin
grid.plugins = [CustomHighlightPlugin];Service providers available to plugins for accessing grid functionality.
/**
* Plugin providers interface - access to all grid services
*/
interface PluginProviders {
/** Data management provider */
data: DataProvider;
/** Column management provider */
column: ColumnDataProvider;
/** Dimension calculation provider */
dimension: DimensionProvider;
/** Viewport management provider */
viewport: ViewportProvider;
/** Selection state provider */
selection: SelectionStoreConnector;
/** Plugin service for plugin management */
plugins: PluginService;
}
/**
* Data provider interface for plugin access
*/
interface DataProvider {
setData(source: DataType[], type: DimensionRows, disableVirtual?: boolean): void;
setCellData(details: SetCellData, refresh?: boolean): void;
setRangeData(data: RangeUpdateData, type: DimensionRows): void;
refresh(type?: DimensionRows): void;
changeOrder(details: RowOrderChangeDetails): void;
setTrimmed(trimmed: Record<number, boolean>, type: DimensionRows): void;
}
/**
* Column provider interface for plugin access
*/
interface ColumnDataProvider {
setColumns(collection: ColumnCollection): void;
updateColumns(cols: ColumnRegular[]): void;
getColumns(): ColumnRegular[];
getColumn(index: number, type: DimensionCols): ColumnRegular | undefined;
getColumnIndexByProp(prop: ColumnProp, type: DimensionCols): number;
}Usage Example:
class DataExportPlugin extends BasePlugin {
exportData() {
// Access data through provider
const dataProvider = this.providers.data;
const columnProvider = this.providers.column;
// Get current data and columns
const columns = columnProvider.getColumns();
const sourceStore = this.providers.data.getSourceStore();
const data = sourceStore.get().source;
// Export logic here
this.exportToCSV(data, columns);
}
private exportToCSV(data: DataType[], columns: ColumnRegular[]) {
// CSV export implementation
}
}Pre-built plugins available for common functionality.
/**
* Auto-size column plugin for automatic column width adjustment
*/
class AutoSizeColumnPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Filter plugin for column filtering functionality
*/
class FilterPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Sorting plugin for column sorting functionality
*/
class SortingPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Export plugin for data export functionality
*/
class ExportFilePlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Row grouping plugin for hierarchical data display
*/
class GroupingRowPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Column move plugin for drag-and-drop column reordering
*/
class ColumnMovePlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Column stretch plugin for responsive column sizing
*/
class StretchColumn extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Accessibility plugin for WAI-ARIA compliance
*/
class WCAGPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}
/**
* Right-to-left support plugin
*/
class RTLPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders);
}Usage Example:
import {
FilterPlugin,
SortingPlugin,
AutoSizeColumnPlugin
} from '@revolist/revogrid';
// Enable built-in plugins
grid.plugins = [
FilterPlugin,
SortingPlugin,
AutoSizeColumnPlugin
];Configuration options for enabling and customizing plugins.
/**
* Grid plugin definition - can be class constructor or instance
*/
type GridPlugin = PluginConstructor | PluginInstance;
/**
* Plugin constructor type
*/
type PluginConstructor = new (
revogrid: HTMLRevoGridElement,
providers: PluginProviders
) => BasePlugin;
/**
* Plugin instance type
*/
interface PluginInstance extends BasePlugin {
destroy(): void;
}
/**
* Watch configuration options
*/
interface WatchOptions {
/** Execute immediately with current value */
immediate?: boolean;
/** Deep watch for object changes */
deep?: boolean;
}Usage Example:
// Using constructor
class MyPlugin extends BasePlugin {
// Plugin implementation
}
// Using instance (for plugins with configuration)
class ConfigurablePlugin extends BasePlugin {
constructor(
revogrid: HTMLRevoGridElement,
providers: PluginProviders,
public config: { theme: string; enabled: boolean }
) {
super(revogrid, providers);
}
}
// Register plugins
grid.plugins = [
MyPlugin, // Constructor
new ConfigurablePlugin(grid, providers, { theme: 'dark', enabled: true }) // Instance
];Managing plugin lifecycle and cleanup.
/**
* Plugin service for managing plugin lifecycle
*/
interface PluginService {
/** Register a new plugin */
register(plugin: GridPlugin): void;
/** Unregister a plugin */
unregister(plugin: GridPlugin): void;
/** Get all active plugins */
getPlugins(): PluginBaseComponent[];
/** Destroy all plugins */
destroyAll(): void;
}
/**
* Plugin base component interface
*/
interface PluginBaseComponent {
/** Plugin name/identifier */
name?: string;
/** Destroy plugin and clean up */
destroy(): void;
}Usage Example:
class LifecyclePlugin extends BasePlugin {
name = 'lifecycle-plugin';
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders) {
super(revogrid, providers);
console.log('Plugin initialized');
}
destroy() {
console.log('Plugin destroyed');
super.destroy();
}
}
// Register plugin
grid.plugins = [LifecyclePlugin];
// Later, get active plugins
const plugins = await grid.getPlugins();
console.log('Active plugins:', plugins.map(p => p.name));Advanced event handling and custom event creation in plugins.
/**
* Custom event map for type-safe event handling
*/
interface CustomEventMap {
// Data events
beforeedit: BeforeSaveDataDetails;
afteredit: AfterEditEvent;
// Selection events
beforecellfocus: BeforeSaveDataDetails;
afterfocus: FocusAfterRenderEvent;
// Column events
beforecolumnsset: ColumnCollection;
aftercolumnsset: { columns: ColumnRegular[]; order: Record<string, number> };
// Custom plugin events
[key: string]: any;
}
/**
* Event detail types
*/
interface BeforeSaveDataDetails {
val: any;
oldVal: any;
row: DataType;
col: ColumnRegular;
models: DataType[];
}
interface AfterEditEvent {
val: any;
oldVal: any;
row: DataType;
col: ColumnRegular;
models: DataType[];
}Usage Example:
class EventPlugin extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders) {
super(revogrid, providers);
// Type-safe event listening
this.addEventListener('afteredit', this.onAfterEdit);
this.addEventListener('beforecolumnsset', this.onBeforeColumnsSet);
}
private onAfterEdit = (event: CustomEvent<AfterEditEvent>) => {
const { val, oldVal, row, col } = event.detail;
console.log(`Cell ${col.prop} changed from ${oldVal} to ${val}`);
// Emit custom event
this.emit('custom-data-changed', {
column: col.prop,
newValue: val,
row: row
});
};
private onBeforeColumnsSet = (event: CustomEvent<ColumnCollection>) => {
console.log('Columns will be set:', event.detail);
};
}Inter-plugin communication and data sharing.
/**
* Plugin registry for cross-plugin communication
*/
interface PluginRegistry {
/** Register plugin with name */
register(name: string, plugin: BasePlugin): void;
/** Get plugin by name */
get(name: string): BasePlugin | undefined;
/** Check if plugin exists */
has(name: string): boolean;
/** Send message to plugin */
sendMessage(targetPlugin: string, message: any): void;
}Usage Example:
class ProducerPlugin extends BasePlugin {
name = 'producer';
shareData() {
// Share data with other plugins
this.emit('plugin-data-share', {
from: this.name,
data: { status: 'active', count: 100 }
});
}
}
class ConsumerPlugin extends BasePlugin {
name = 'consumer';
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders) {
super(revogrid, providers);
// Listen for shared data
this.addEventListener('plugin-data-share', this.onDataReceived);
}
private onDataReceived = (event: CustomEvent) => {
const { from, data } = event.detail;
console.log(`Received data from ${from}:`, data);
};
}