Skip to content

Commit 03637e4

Browse files
authored
fix(React): assign CustomDataView to SharedService, fixes #2614 (#2617)
* fix: assign CustomDataView to SharedService, fixes #2614
1 parent e009b11 commit 03637e4

6 files changed

Lines changed: 82 additions & 54 deletions

File tree

frameworks/aurelia-slickgrid/src/custom-elements/aurelia-slickgrid.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
BackendServiceOption,
66
BasePaginationComponent,
77
Column,
8+
CustomDataView,
89
DataViewOption,
910
EventSubscription,
1011
ExtensionList,
@@ -146,7 +147,7 @@ export class AureliaSlickgridCustomElement {
146147
@bindable({ mode: BindingMode.twoWay }) totalItems = 0;
147148
@bindable({ mode: BindingMode.fromView }) extensions!: ExtensionList<any>;
148149
@bindable({ mode: BindingMode.fromView }) instances: AureliaGridInstance | null = null;
149-
@bindable() customDataView?: SlickDataView;
150+
@bindable() customDataView?: CustomDataView;
150151
@bindable() dataset: any[] = [];
151152
@bindable() datasetHierarchical?: any[] | null;
152153
@bindable() gridId = '';

frameworks/slickgrid-react/src/components/slickgrid-react.tsx

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
type BackendServiceOption,
3030
type BasePaginationComponent,
3131
type Column,
32+
type CustomDataView,
3233
type DataViewOption,
3334
type EventSubscription,
3435
type ExtensionList,
@@ -159,7 +160,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
159160
sortService: SortService;
160161
treeDataService: TreeDataService;
161162

162-
dataView!: SlickDataView<TData>;
163+
dataView!: SlickDataView<TData> | CustomDataView<TData>;
163164
grid!: SlickGrid;
164165
totalItems = 0;
165166

@@ -176,7 +177,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
176177
};
177178

178179
get dataset(): any[] {
179-
return this.dataView?.getItems() || [];
180+
return this.dataView?.getItems?.() || [];
180181
}
181182
set dataset(newDataset: any[]) {
182183
const prevDatasetLn = this._currentDatasetLength;
@@ -221,19 +222,21 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
221222
}
222223

223224
// when a hierarchical dataset is set afterward, we can reset the flat dataset and call a tree data sort that will overwrite the flat dataset
224-
if (this.dataView && newHierarchicalDataset && this.grid && this.sortService?.processTreeDataInitialSort) {
225+
if (this.dataView?.setItems && newHierarchicalDataset && this.grid && this.sortService?.processTreeDataInitialSort) {
225226
this.dataView.setItems([], this._options?.datasetIdPropertyName ?? 'id');
226227
this.sortService.processTreeDataInitialSort();
227228
this.treeDataService.initHierarchicalTree();
228229

229230
// we also need to reset/refresh the Tree Data filters because if we inserted new item(s) then it might not show up without doing this refresh
230231
// however we need to queue our process until the flat dataset is ready, so we can queue a microtask to execute the DataView refresh only after everything is ready
231-
queueMicrotask(() => {
232-
const flatDatasetLn = this.dataView?.getItemCount() ?? 0;
233-
if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) {
234-
this.filterService.refreshTreeDataFilters();
235-
}
236-
});
232+
if ((this.dataView as SlickDataView)?.getItemCount) {
233+
queueMicrotask(() => {
234+
const flatDatasetLn = (this.dataView as SlickDataView).getItemCount();
235+
if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) {
236+
this.filterService.refreshTreeDataFilters();
237+
}
238+
});
239+
}
237240
}
238241

239242
this._isDatasetHierarchicalInitialized = true;
@@ -481,7 +484,9 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
481484
this.createBackendApiInternalPostProcessCallback(this._options);
482485
}
483486

484-
if (!this.props.customDataView) {
487+
if (this.props.customDataView) {
488+
this.dataView = this.props.customDataView;
489+
} else {
485490
const dataviewInlineFilters = (this._options.dataView && this._options.dataView.inlineFilters) || false;
486491
let dataViewOptions: Partial<DataViewOption> = { ...this._options.dataView, inlineFilters: dataviewInlineFilters };
487492

@@ -527,9 +532,9 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
527532
this._eventPubSubService
528533
);
529534
if (typeof (this.dataView as SlickDataView).setGrid === 'function') {
530-
this.dataView.setGrid(this.grid);
535+
(this.dataView as SlickDataView).setGrid(this.grid);
531536
}
532-
this.sharedService.dataView = this.dataView;
537+
this.sharedService.dataView = this.dataView as SlickDataView;
533538
this.sharedService.slickGrid = this.grid;
534539
this.sharedService.gridContainerElement = this._elm as HTMLDivElement;
535540
if (this.groupItemMetadataProvider) {
@@ -568,7 +573,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
568573

569574
if (!this.props.customDataView && this.dataView) {
570575
const initialDataset = this._options?.enableTreeData ? this.sortTreeDataset(this.props.dataset) : this.props.dataset;
571-
if (Array.isArray(initialDataset)) {
576+
if (Array.isArray(initialDataset) && this.dataView.setItems) {
572577
this.dataView.setItems(initialDataset, this._options.datasetIdPropertyName ?? 'id');
573578
}
574579

@@ -589,9 +594,13 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
589594
// when using BackendServiceApi, we'll be using the "syncGridSelectionWithBackendService" flag BUT "syncGridSelection" must also be set to True
590595
preservedRowSelection = syncGridSelection && preservedRowSelectionWithBackend;
591596
}
592-
this.dataView.syncGridSelection(this.grid, preservedRowSelection);
597+
(this.dataView as SlickDataView).syncGridSelection?.(this.grid, preservedRowSelection);
593598
} else if (typeof syncGridSelection === 'object') {
594-
this.dataView.syncGridSelection(this.grid, syncGridSelection.preserveHidden, syncGridSelection.preserveHiddenOnSelectionChange);
599+
(this.dataView as SlickDataView).syncGridSelection?.(
600+
this.grid,
601+
syncGridSelection.preserveHidden,
602+
syncGridSelection.preserveHiddenOnSelectionChange
603+
);
595604
}
596605
}
597606

@@ -633,7 +642,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
633642
element: this._elm as HTMLDivElement,
634643

635644
// Slick Grid & DataView objects
636-
dataView: this.dataView,
645+
dataView: this.dataView as SlickDataView,
637646
slickGrid: this.grid,
638647

639648
// public methods
@@ -817,7 +826,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
817826
}
818827
}
819828

820-
bindDifferentHooks(grid: SlickGrid, gridOptions: GridOption, dataView: SlickDataView) {
829+
bindDifferentHooks(grid: SlickGrid, gridOptions: GridOption, dataView: CustomDataView) {
821830
// translate some of them on first load, then on each language change
822831
if (gridOptions.enableTranslate) {
823832
this.extensionService.translateAllExtensions();
@@ -896,29 +905,34 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
896905
this.loadFilterPresetsWhenDatasetInitialized();
897906

898907
// When data changes in the DataView, we need to refresh the metrics and/or display a warning if the dataset is empty
899-
this._eventHandler.subscribe(dataView.onRowCountChanged, (_e, args) => {
900-
if (!gridOptions.enableRowDetailView || !Array.isArray(args.changedRows) || args.changedRows.length === args.itemCount) {
901-
grid.invalidate();
902-
} else {
903-
grid.invalidateRows(args.changedRows);
904-
grid.render();
905-
}
906-
this.handleOnItemCountChanged(dataView.getFilteredItemCount() || 0, dataView.getItemCount() || 0);
907-
});
908-
this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => {
909-
this.sharedService.isItemsDateParsed = false;
910-
this.handleOnItemCountChanged(dataView.getFilteredItemCount() || 0, args.itemCount);
908+
if (dataView.onRowCountChanged?.subscribe) {
909+
this._eventHandler.subscribe(dataView.onRowCountChanged, (_e, args) => {
910+
if (!gridOptions.enableRowDetailView || !Array.isArray(args.changedRows) || args.changedRows.length === args.itemCount) {
911+
grid.invalidate();
912+
} else {
913+
grid.invalidateRows(args.changedRows);
914+
grid.render();
915+
}
916+
this.handleOnItemCountChanged(dataView.getFilteredItemCount?.() || 0, dataView.getItemCount?.() || 0);
917+
});
918+
}
911919

912-
// when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset
913-
if (
914-
args.itemCount > 0 &&
915-
(this.options.autosizeColumnsByCellContentOnFirstLoad || this.options.enableAutoResizeColumnsByCellContent)
916-
) {
917-
this.resizerService.resizeColumnsByCellContent(!this._options?.resizeByContentOnlyOnFirstLoad);
918-
}
919-
});
920+
if (dataView.onSetItemsCalled?.subscribe) {
921+
this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => {
922+
this.sharedService.isItemsDateParsed = false;
923+
this.handleOnItemCountChanged(dataView.getFilteredItemCount?.() || 0, args.itemCount);
924+
925+
// when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset
926+
if (
927+
args.itemCount > 0 &&
928+
(this.options.autosizeColumnsByCellContentOnFirstLoad || this.options.enableAutoResizeColumnsByCellContent)
929+
) {
930+
this.resizerService.resizeColumnsByCellContent(!this._options?.resizeByContentOnlyOnFirstLoad);
931+
}
932+
});
933+
}
920934

921-
if (gridOptions?.enableFiltering && !gridOptions.enableRowDetailView) {
935+
if (gridOptions?.enableFiltering && !gridOptions.enableRowDetailView && dataView.onRowsChanged?.subscribe) {
922936
this._eventHandler.subscribe(dataView.onRowsChanged, (_e, { calledOnRowCountChanged, rows }) => {
923937
// filtering data with local dataset will not always show correctly unless we call this updateRow/render
924938
// 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<TData = any> extends React.Component<SlickgridReactP
11601174
if (Array.isArray(dataset) && this.grid && this.dataView?.setItems) {
11611175
this.dataView.setItems(dataset, this._options.datasetIdPropertyName ?? 'id');
11621176
if (!this._options.backendServiceApi && !this._options.enableTreeData) {
1163-
this.dataView.reSort();
1177+
(this.dataView as SlickDataView).reSort?.();
11641178
}
11651179

11661180
if (dataset.length > 0) {
@@ -1397,8 +1411,8 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
13971411
protected loadLocalGridPagination(dataset?: any[]) {
13981412
if (this._options && this._paginationOptions) {
13991413
this.totalItems = Array.isArray(dataset) ? dataset.length : 0;
1400-
if (this._paginationOptions && this.dataView?.getPagingInfo) {
1401-
const slickPagingInfo = this.dataView.getPagingInfo();
1414+
if (this._paginationOptions && (this.dataView as SlickDataView)?.getPagingInfo) {
1415+
const slickPagingInfo = (this.dataView as SlickDataView).getPagingInfo();
14021416
if (slickPagingInfo?.hasOwnProperty('totalRows') && this._paginationOptions.totalItems !== slickPagingInfo.totalRows) {
14031417
this.totalItems = slickPagingInfo.totalRows || 0;
14041418
}
@@ -1425,15 +1439,15 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
14251439

14261440
// maps the IDs to the Grid Rows and vice versa, the "dataContextIds" has precedence over the other
14271441
if (Array.isArray(dataContextIds) && dataContextIds.length > 0) {
1428-
gridRowIndexes = this.dataView.mapIdsToRows(dataContextIds) || [];
1442+
gridRowIndexes = (this.dataView as SlickDataView).mapIdsToRows?.(dataContextIds) || [];
14291443
} else if (Array.isArray(gridRowIndexes) && gridRowIndexes.length > 0) {
1430-
dataContextIds = this.dataView.mapRowsToIds(gridRowIndexes) || [];
1444+
dataContextIds = (this.dataView as SlickDataView).mapRowsToIds?.(gridRowIndexes) || [];
14311445
}
14321446

14331447
// apply row selection when defined as grid presets
14341448
if (this.grid && Array.isArray(gridRowIndexes)) {
14351449
this.grid.setSelectedRows(gridRowIndexes);
1436-
this.dataView!.setSelectedIds(dataContextIds || [], {
1450+
(this.dataView as SlickDataView).setSelectedIds?.(dataContextIds || [], {
14371451
isRowBeingAdded: true,
14381452
shouldTriggerEvent: false, // do not trigger when presetting the grid
14391453
applyRowSelectionToGrid: true,
@@ -1617,7 +1631,7 @@ export class SlickgridReact<TData = any> extends React.Component<SlickgridReactP
16171631

16181632
protected suggestDateParsingWhenHelpful() {
16191633
if (
1620-
this.dataView?.getItemCount() > WARN_NO_PREPARSE_DATE_SIZE &&
1634+
((this.dataView as SlickDataView)?.getItemCount?.() ?? 0) > WARN_NO_PREPARSE_DATE_SIZE &&
16211635
!this.options.silenceWarnings &&
16221636
!this.options.preParseDateColumns &&
16231637
this.grid.getColumns().some((c) => isColumnDateType(c.type))

frameworks/slickgrid-react/src/components/slickgridReactProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
ContainerService,
44
CurrentFilter,
55
CurrentSorter,
6+
CustomDataView,
67
DragRowMove,
78
ExportTextDownloadOption,
89
ExtensionList,
@@ -71,7 +72,6 @@ import type {
7172
ReactSlickEventHandler,
7273
SingleColumnSort,
7374
SlickControlList,
74-
SlickDataView,
7575
SlickGrid,
7676
SlickPluginList,
7777
SlickRange,
@@ -85,7 +85,7 @@ export interface SlickgridReactProps {
8585
footer?: React.ReactElement;
8686
containerService: ContainerService;
8787
translaterService?: TranslaterI18NextService;
88-
customDataView?: SlickDataView;
88+
customDataView?: CustomDataView;
8989
dataset: any[];
9090
datasetHierarchical?: any[] | null;
9191
extensions?: ExtensionList<SlickControlList | SlickPluginList>;

packages/common/src/core/slickGrid.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3801,7 +3801,7 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
38013801
* @returns {ItemMetadata | null}
38023802
*/
38033803
getItemMetadaWhenExists(row: number): ItemMetadata | null {
3804-
return 'getItemMetadata' in this.data ? (this.data as CustomDataView<TData>).getItemMetadata(row) : null;
3804+
return 'getItemMetadata' in this.data ? (this.data as SlickDataView<TData>).getItemMetadata(row) : null;
38053805
}
38063806

38073807
/** Get Top Panel DOM element */

packages/common/src/interfaces/gridOption.interface.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { BasePubSubService, EventNamingStyle } from '@slickgrid-universal/event-pub-sub';
22
import type { MultipleSelectOption } from 'multiple-select-vanilla';
33
import type { TrustedHTML } from 'trusted-types/lib';
4-
import type { DataViewOption, SlickEditorLock } from '../core/index.js';
4+
import type { DataViewOption, SlickEditorLock, SlickEvent, SlickGrid } from '../core/index.js';
55
import type { ColumnReorderFunction, OperatorType } from '../enums/index.js';
66
import type { TranslaterService } from '../services/translater.service.js';
77
import type {
@@ -59,9 +59,22 @@ export interface CellViewportRange {
5959
}
6060

6161
export interface CustomDataView<T = any> {
62-
getItem: (index: number) => T;
63-
getItemMetadata(row: number, cell?: boolean | number): ItemMetadata | null;
64-
getLength: () => number;
62+
getItem(index: number): T;
63+
getItemMetadata?: (row: number, cell?: boolean | number) => ItemMetadata | null;
64+
getLength(): number;
65+
getItemCount?: () => number;
66+
getFilteredItemCount?: () => number;
67+
getItems?: () => T[];
68+
setItems?: (data: T[]) => void;
69+
setGrid?: (grid: SlickGrid) => void;
70+
refresh?: (...args: any[]) => void;
71+
destroy?: () => void;
72+
dispose?: () => void;
73+
74+
onRowCountChanged?: SlickEvent;
75+
onRowsChanged?: SlickEvent;
76+
onSelectedRowIdsChanged?: SlickEvent;
77+
onSetItemsCalled?: SlickEvent;
6578
}
6679

6780
export interface CssStyleHash {

packages/utils/src/domUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function calculateAvailableSpace(element: HTMLElement): { top: number; bo
1717
const vh = window.innerHeight;
1818
const vw = window.innerWidth;
1919
const { top: pageScrollTop, left: pageScrollLeft } = windowScrollPosition();
20-
const { top: elementOffsetTop = 0, left: elementOffsetLeft = 0 } = getOffset(element) ?? {};
20+
const { top: elementOffsetTop, left: elementOffsetLeft } = getOffset(element) ?? {};
2121

2222
const top = elementOffsetTop - pageScrollTop;
2323
const left = elementOffsetLeft - pageScrollLeft;

0 commit comments

Comments
 (0)