UNPKG

@syncfusion/ej2-spreadsheet

Version:

Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel

114 lines (92 loc) 8.42 kB
# Filter Module data flow ## What It Does Filter subsystem enables Excel-like filtering for ranges: it computes predicates, builds filter UI (popup, checkbox tree, custom dialogs), applies predicates to sheet data (via DataManager/getData), and hides/unhides rows. It supports virtualized sheets, frozen panes, context-menu sorting/filtering hooks, and integrates with the workbook action pipeline. Primary implementation files: `src/spreadsheet/integrations/filter.ts` (UI) and `src/workbook/integrations/filter.ts` (Core). ## Entry Points (UI) **Class:** `Filter` (`src/spreadsheet/integrations/filter.ts`) - Listens / handles: `initiateFilterUI`, `filterRangeAlert`, `mouseDown`, `renderFilterCell`, `refreshFilterRange`, `updateSortCollection`, `beforeFltrcMenuOpen`, `filterByCellValue`, `clearFilter`, `getFilteredColumn`, `cMenuBeforeOpen`, `filterDialogCreated`, `filterDialogClose`, `reapplyFilter`, `beforeInsert`, `beforeDelete`, `moveSheetHandler`, `duplicateSheetFilterHandler`, `contentLoaded` and related UI lifecycle events. - Key handlers: - `initiateFilterUIHandler()` — entry for user-driven filter actions and programmatic filter requests; validates range and prepares `FilterOptions`/`PredicateModel[]`. - `renderFilterCellHandler()` — renders filter buttons/icons in header cells and attaches popup triggers. - `openDialog()` / `initCboxList()` / `initTreeView()` — build filter popup UI, list values, tree-view/checkbox interaction and apply/cancel flow. - `filterByCellValueHandler()` — quick filter creation from active cell value (equal predicate). - `refreshFilterRange()` — updates header UI and filter buttons after structural changes. - `filterSuccessHandler()` / `applyFilter()` — commit predicates to the filter collection and notify core to apply. ## Entry Points (Core) **Class:** `WorkbookFilter` (`src/workbook/integrations/filter.ts`) - Listens: `initiateFilter` event. - Key handlers: - `initiateFilterHandler()` — receives `BeforeFilterEventArgs` and either uses provided `FilterOptions.datasource` or calls `getData()` for the sheet range, then delegates to `setFilter()`. - `setFilter()` — evaluate DataManager predicates, compute rows to hide/unhide, and call `setRow()` or notify `hideShow` for UI updates (supports virtualization paths). - `destroy()` / lifecycle cleanup. ## ASCII Core Logic Flow User opens filter UI (or selects filter action) ↓ `Filter.initiateFilterUIHandler()` validates range → builds `FilterOptions` and `PredicateModel[]` ↓ UI calls/dispatches `initiateFilter` event (or core invoked directly) with args and promise ↓ `WorkbookFilter.initiateFilterHandler()` fetches data (via `getData` or uses `dataManager`), then calls `setFilter()` ↓ `setFilter()` computes `result` (matching rows) with `applyPredicates()` → for rows not matching set `row.hidden = true` and `row.isFiltered = true` ↓ If virtualized or large sheet: notify `hideShow` per batch; else call `setRow()` in-place and trigger `renderModule.refreshSheet()` as needed ↓ UI `Filter` updates header icons/buttons (`e-filter-btn`), filter popup state and sort/filter menu items; operations are recorded via `beginAction` for undo/redo. ## Operations (functions & responsibilities) - `initiateFilterUIHandler(args)` (UI) - Validate the requested range (`isInValidFilterRange()`), compute effective header and filter range, assemble `eventArgs` and call `parent.notify(initiateFilter, { args, promise })` when applying filters asynchronously. - Support options: `predicates`, `range`, `isCut/isInternal`, `useFilterRange`, `allowHeaderFilter`. - `renderFilterCellHandler(args)` (UI) - Create and inject filter button element (`e-filter-btn`) into header cell and attach popup behavior. - `getPredicateRange(range, predicates, col?)` (UI helper) - Return compact predicate address string for incremental predicate application and display. - `initCboxList()` / `initTreeView()` (UI) - Build checkbox list/tree for filter popup, handle selection, search, select-all, and UI state updates. - `filterByCellValueHandler()` (UI) - Convert active cell value into an equality predicate and trigger `initiateFilterUI` flow. - `applyFilter(filterOptions, range, sheetIdx, prevPredicates, refresh, isInternal)` (UI) - Wraps the final step: calls `parent.notify(initiateFilter, ...)` or directly triggers core setFilter depending on sync flags. - `initiateFilterHandler(eventArgs)` (Core) - If `filterOptions.datasource` is provided, use it; otherwise call `getData(this.parent, sheetName!address)` to fetch row JSON. - Create a `DataManager` (or use provided) and compute matching rows via `applyPredicates()`. - Delegate to `setFilter()` for row hide/unhide actions. - `setFilter(dataManager, predicates, range, refresh, equalOrPredicates?)` (Core) - Uses `applyPredicates` to compute result set; iterates JSON rows and marks non-matching rows as hidden/isFiltered via `setRow()`. - For virtualized sheets or large datasets, batch-notify `hideShow` to update UI incrementally and preserve scroll/top-left cell. - Triggers `renderModule.refreshSheet()` for final UI repaint when required. ## Validation & Safety - Range validation: `isInValidFilterRange()` prevents filtering outside of usedRange or on empty sheets. - Begin/Cancel workflow: `beginAction` event allows cancellation of filter action; `eventArgs.cancel` is respected. - Promise/async safety: `initiateFilterHandler()` returns/uses a `Deferred.promise` so UI can await data fetch completion (`getData`) before UI updates. - Virtualization and frozen panes: `setFilter()` distinguishes virtualized vs. normal rendering paths to avoid O(N) DOM updates and preserve viewport and frozen-row/col behavior. - Structural changes handling: `beforeInsert` / `beforeDelete` / `moveSheetHandler` remove or shift filter metadata safely via helper handlers. - Undo/Redo: `beginAction` integration ensures filter actions can be recorded; handlers honor `isInternal`/`isCut` flags to avoid double-applying during clipboard moves. ## Desired Outputs User-facing - Filter popup with value checklist (checkbox list or tree) and search, custom filter dialog, and Apply/Clear UI. - Filter icons/buttons in header cells (`e-filter-btn`) showing active status and enabling popup. - Context-menu and filter-specific sort items integrated into right-click menus. - Responsive behavior for large data/virtualized sheets with progressive hide/unhide updates. System-level - Events & Notifications: - UI → Core: `initiateFilter` (apply filter with args + promise) - UI local hooks: `initiateFilterUI`, `filterByCellValue`, `reapplyFilter`, `clearFilter`, `getFilteredColumn`, `cMenuBeforeOpen` - Core → UI integrations: `hideShow` (batch hide/unhide), `renderModule.refreshSheet()` (refresh), `getData` usage for fetching sheet JSON - Action pipeline: `beginAction` for recording filter ops (cancellable) - Model artifacts: - `filterRange` Map (sheetIdx → { useFilterRange, range: number[], allowHeaderFilter }) stored in UI module. - `filterCollection` Map (sheetIdx → PredicateModel[]) storing applied predicates. - Row state: `RowModel.hidden` and `RowModel.isFiltered` toggled by core `setFilter()`. - DOM / CSS hooks: - Filter button class: `e-filter-btn` and icon `e-filter-icon` / `e-filter-iconbtn`. - Popup class: `e-filter-popup` for filter dialog, and `e-spreadsheet-contextmenu` used when adding filter context items. - Undo/Redo records: - Filtering operations are emitted via `beginAction` and can be captured by the workbook action pipeline so filter apply/clear can be undone/redone. ## Implementation Notes (short) - Keep UI/core separation: `Filter` builds predicates and manages popup UI; `WorkbookFilter` evaluates data and mutates row state. - Use `DataManager` for performant predicate application and `applyPredicates()` helper to produce the matched set. - Always validate ranges against `usedRange` and prefer early rejection with `filterRangeAlertHandler()` for invalid requests. - For virtualized sheets, prefer `hideShow` notifications for incremental updates to avoid full re-renders; call `renderModule.refreshSheet()` only when necessary. - Ensure `setFilteredCollection()` serializes `filterRange` and `filterCollection` for save/serialize operations. ---