From 1639650286be91d03cc06aeef5c112cc9b7d1fbb Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 16 Jun 2026 22:03:41 -0400 Subject: [PATCH 1/3] fix: assign CustomDataView to SharedService, fixes #2614 --- .../src/components/slickgrid-react.tsx | 98 +++++++++++-------- .../src/components/slickgridReactProps.ts | 4 +- packages/common/src/core/slickGrid.ts | 2 +- .../src/interfaces/gridOption.interface.ts | 21 +++- packages/utils/src/domUtils.ts | 2 +- 5 files changed, 77 insertions(+), 50 deletions(-) diff --git a/frameworks/slickgrid-react/src/components/slickgrid-react.tsx b/frameworks/slickgrid-react/src/components/slickgrid-react.tsx index 1792f0ad5..4b2117385 100644 --- a/frameworks/slickgrid-react/src/components/slickgrid-react.tsx +++ b/frameworks/slickgrid-react/src/components/slickgrid-react.tsx @@ -29,6 +29,7 @@ import { type BackendServiceOption, type BasePaginationComponent, type Column, + type CustomDataView, type DataViewOption, type EventSubscription, type ExtensionList, @@ -159,7 +160,7 @@ export class SlickgridReact extends React.Component; + dataView!: SlickDataView | CustomDataView; grid!: SlickGrid; totalItems = 0; @@ -228,12 +229,14 @@ export class SlickgridReact extends React.Component { - const flatDatasetLn = this.dataView?.getItemCount() ?? 0; - if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) { - this.filterService.refreshTreeDataFilters(); - } - }); + if ((this.dataView as SlickDataView)?.getItemCount) { + queueMicrotask(() => { + const flatDatasetLn = (this.dataView as SlickDataView).getItemCount(); + if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) { + this.filterService.refreshTreeDataFilters(); + } + }); + } } this._isDatasetHierarchicalInitialized = true; @@ -481,7 +484,9 @@ export class SlickgridReact extends React.Component = { ...this._options.dataView, inlineFilters: dataviewInlineFilters }; @@ -527,9 +532,9 @@ export class SlickgridReact extends React.Component extends React.Component extends React.Component extends React.Component extends React.Component { - if (!gridOptions.enableRowDetailView || !Array.isArray(args.changedRows) || args.changedRows.length === args.itemCount) { - grid.invalidate(); - } else { - grid.invalidateRows(args.changedRows); - grid.render(); - } - this.handleOnItemCountChanged(dataView.getFilteredItemCount() || 0, dataView.getItemCount() || 0); - }); - this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => { - this.sharedService.isItemsDateParsed = false; - this.handleOnItemCountChanged(dataView.getFilteredItemCount() || 0, args.itemCount); + if (dataView.onRowCountChanged?.subscribe) { + this._eventHandler.subscribe(dataView.onRowCountChanged, (_e, args) => { + if (!gridOptions.enableRowDetailView || !Array.isArray(args.changedRows) || args.changedRows.length === args.itemCount) { + grid.invalidate(); + } else { + grid.invalidateRows(args.changedRows); + grid.render(); + } + this.handleOnItemCountChanged(dataView.getFilteredItemCount?.() || 0, dataView.getItemCount?.() || 0); + }); + } - // when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset - if ( - args.itemCount > 0 && - (this.options.autosizeColumnsByCellContentOnFirstLoad || this.options.enableAutoResizeColumnsByCellContent) - ) { - this.resizerService.resizeColumnsByCellContent(!this._options?.resizeByContentOnlyOnFirstLoad); - } - }); + if (dataView.onSetItemsCalled?.subscribe) { + this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => { + this.sharedService.isItemsDateParsed = false; + this.handleOnItemCountChanged(dataView.getFilteredItemCount?.() || 0, args.itemCount); + + // when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset + if ( + args.itemCount > 0 && + (this.options.autosizeColumnsByCellContentOnFirstLoad || this.options.enableAutoResizeColumnsByCellContent) + ) { + this.resizerService.resizeColumnsByCellContent(!this._options?.resizeByContentOnlyOnFirstLoad); + } + }); + } - if (gridOptions?.enableFiltering && !gridOptions.enableRowDetailView) { + if (gridOptions?.enableFiltering && !gridOptions.enableRowDetailView && dataView.onRowsChanged?.subscribe) { this._eventHandler.subscribe(dataView.onRowsChanged, (_e, { calledOnRowCountChanged, rows }) => { // filtering data with local dataset will not always show correctly unless we call this updateRow/render // also don't use "invalidateRows" since it destroys the entire row and as bad user experience when updating a row @@ -1160,7 +1174,7 @@ export class SlickgridReact extends React.Component 0) { @@ -1397,8 +1411,8 @@ export class SlickgridReact extends React.Component extends React.Component 0) { - gridRowIndexes = this.dataView.mapIdsToRows(dataContextIds) || []; + gridRowIndexes = (this.dataView as SlickDataView).mapIdsToRows?.(dataContextIds) || []; } else if (Array.isArray(gridRowIndexes) && gridRowIndexes.length > 0) { - dataContextIds = this.dataView.mapRowsToIds(gridRowIndexes) || []; + dataContextIds = (this.dataView as SlickDataView).mapRowsToIds?.(gridRowIndexes) || []; } // apply row selection when defined as grid presets if (this.grid && Array.isArray(gridRowIndexes)) { this.grid.setSelectedRows(gridRowIndexes); - this.dataView!.setSelectedIds(dataContextIds || [], { + (this.dataView as SlickDataView).setSelectedIds?.(dataContextIds || [], { isRowBeingAdded: true, shouldTriggerEvent: false, // do not trigger when presetting the grid applyRowSelectionToGrid: true, @@ -1617,7 +1631,7 @@ export class SlickgridReact extends React.Component WARN_NO_PREPARSE_DATE_SIZE && + ((this.dataView as SlickDataView)?.getItemCount?.() ?? 0) > WARN_NO_PREPARSE_DATE_SIZE && !this.options.silenceWarnings && !this.options.preParseDateColumns && this.grid.getColumns().some((c) => isColumnDateType(c.type)) diff --git a/frameworks/slickgrid-react/src/components/slickgridReactProps.ts b/frameworks/slickgrid-react/src/components/slickgridReactProps.ts index 9a3afd33e..48674d000 100644 --- a/frameworks/slickgrid-react/src/components/slickgridReactProps.ts +++ b/frameworks/slickgrid-react/src/components/slickgridReactProps.ts @@ -3,6 +3,7 @@ import type { ContainerService, CurrentFilter, CurrentSorter, + CustomDataView, DragRowMove, ExportTextDownloadOption, ExtensionList, @@ -71,7 +72,6 @@ import type { ReactSlickEventHandler, SingleColumnSort, SlickControlList, - SlickDataView, SlickGrid, SlickPluginList, SlickRange, @@ -85,7 +85,7 @@ export interface SlickgridReactProps { footer?: React.ReactElement; containerService: ContainerService; translaterService?: TranslaterI18NextService; - customDataView?: SlickDataView; + customDataView?: CustomDataView; dataset: any[]; datasetHierarchical?: any[] | null; extensions?: ExtensionList; diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index db6fa8518..6362e7412 100755 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -3801,7 +3801,7 @@ export class SlickGrid = Column, O e * @returns {ItemMetadata | null} */ getItemMetadaWhenExists(row: number): ItemMetadata | null { - return 'getItemMetadata' in this.data ? (this.data as CustomDataView).getItemMetadata(row) : null; + return 'getItemMetadata' in this.data ? (this.data as SlickDataView).getItemMetadata(row) : null; } /** Get Top Panel DOM element */ diff --git a/packages/common/src/interfaces/gridOption.interface.ts b/packages/common/src/interfaces/gridOption.interface.ts index f54846327..6146b596b 100644 --- a/packages/common/src/interfaces/gridOption.interface.ts +++ b/packages/common/src/interfaces/gridOption.interface.ts @@ -1,7 +1,7 @@ import type { BasePubSubService, EventNamingStyle } from '@slickgrid-universal/event-pub-sub'; import type { MultipleSelectOption } from 'multiple-select-vanilla'; import type { TrustedHTML } from 'trusted-types/lib'; -import type { DataViewOption, SlickEditorLock } from '../core/index.js'; +import type { DataViewOption, SlickEditorLock, SlickEvent, SlickGrid } from '../core/index.js'; import type { ColumnReorderFunction, OperatorType } from '../enums/index.js'; import type { TranslaterService } from '../services/translater.service.js'; import type { @@ -59,9 +59,22 @@ export interface CellViewportRange { } export interface CustomDataView { - getItem: (index: number) => T; - getItemMetadata(row: number, cell?: boolean | number): ItemMetadata | null; - getLength: () => number; + getItem(index: number): T; + getItemMetadata?: (row: number, cell?: boolean | number) => ItemMetadata | null; + getLength(): number; + getItemCount?: () => number; + getFilteredItemCount?: () => number; + getItems: () => T[]; + setItems: (data: T[]) => void; + setGrid?: (grid: SlickGrid) => void; + refresh?: (...args: any[]) => void; + destroy?: () => void; + dispose?: () => void; + + onRowCountChanged?: SlickEvent; + onRowsChanged?: SlickEvent; + onSelectedRowIdsChanged?: SlickEvent; + onSetItemsCalled?: SlickEvent; } export interface CssStyleHash { diff --git a/packages/utils/src/domUtils.ts b/packages/utils/src/domUtils.ts index 0ee574ce0..2abe2d420 100644 --- a/packages/utils/src/domUtils.ts +++ b/packages/utils/src/domUtils.ts @@ -17,7 +17,7 @@ export function calculateAvailableSpace(element: HTMLElement): { top: number; bo const vh = window.innerHeight; const vw = window.innerWidth; const { top: pageScrollTop, left: pageScrollLeft } = windowScrollPosition(); - const { top: elementOffsetTop = 0, left: elementOffsetLeft = 0 } = getOffset(element) ?? {}; + const { top: elementOffsetTop, left: elementOffsetLeft } = getOffset(element) ?? {}; const top = elementOffsetTop - pageScrollTop; const left = elementOffsetLeft - pageScrollLeft; From 3a7d3a01391ae2160cae0f15f3671939b00dd992 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 16 Jun 2026 22:14:43 -0400 Subject: [PATCH 2/3] chore: add proper Custom DataView type --- .../aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frameworks/aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts b/frameworks/aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts index dbd7d663d..cd935bb6b 100644 --- a/frameworks/aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts +++ b/frameworks/aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts @@ -5,6 +5,7 @@ import type { BackendServiceOption, BasePaginationComponent, Column, + CustomDataView, DataViewOption, EventSubscription, ExtensionList, @@ -146,7 +147,7 @@ export class AureliaSlickgridCustomElement { @bindable({ mode: BindingMode.twoWay }) totalItems = 0; @bindable({ mode: BindingMode.fromView }) extensions!: ExtensionList; @bindable({ mode: BindingMode.fromView }) instances: AureliaGridInstance | null = null; - @bindable() customDataView?: SlickDataView; + @bindable() customDataView?: CustomDataView; @bindable() dataset: any[] = []; @bindable() datasetHierarchical?: any[] | null; @bindable() gridId = ''; From 71714aeb9fcc98ff23876116fe42c804e32ed731 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 16 Jun 2026 23:18:47 -0400 Subject: [PATCH 3/3] chore: make CustomDataView get/setItems as optional --- .../slickgrid-react/src/components/slickgrid-react.tsx | 6 +++--- packages/common/src/interfaces/gridOption.interface.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/slickgrid-react/src/components/slickgrid-react.tsx b/frameworks/slickgrid-react/src/components/slickgrid-react.tsx index 4b2117385..5bffdc32c 100644 --- a/frameworks/slickgrid-react/src/components/slickgrid-react.tsx +++ b/frameworks/slickgrid-react/src/components/slickgrid-react.tsx @@ -177,7 +177,7 @@ export class SlickgridReact extends React.Component extends React.Component extends React.Component { getLength(): number; getItemCount?: () => number; getFilteredItemCount?: () => number; - getItems: () => T[]; - setItems: (data: T[]) => void; + getItems?: () => T[]; + setItems?: (data: T[]) => void; setGrid?: (grid: SlickGrid) => void; refresh?: (...args: any[]) => void; destroy?: () => void;