From 399f77039a4d4387cc959df8c176626a3b288f23 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Thu, 3 Jun 2021 15:58:07 -0400 Subject: [PATCH] fix(tree): calling updateItems should not lose the Tree collapsing icon - calling an update of an row item that is a parent item (with collapse/expand icon) should keep their icon even after an update, it was losing the icon because the Tree structure gets lost and we need to recreate it --- .../services/__tests__/grid.service.spec.ts | 46 +++++++++++++++++++ .../services/grid.service.ts | 10 ++++ 2 files changed, 56 insertions(+) diff --git a/src/app/modules/angular-slickgrid/services/__tests__/grid.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/grid.service.spec.ts index bdb8ae75a..55f137d4a 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/grid.service.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/grid.service.spec.ts @@ -518,6 +518,52 @@ describe('Grid Service', () => { // reset mock jest.spyOn(gridStub, 'getOptions').mockReturnValue({}); }); + + it('should invalidate and rerender the tree dataset when grid option "enableTreeData" is set when calling "updateItem"', () => { + const mockUpdatedItem = { id: 1, file: 'vacation.txt', size: 2.2, parentId: 0 }; + const mockFlatDataset = [{ id: 0, file: 'documents' }, { id: 1, file: 'vacation.txt', parentId: 0 }, mockUpdatedItem]; + const mockHierarchical = [{ id: 0, file: 'documents', files: [{ id: 1, file: 'vacation.txt' }, mockUpdatedItem] }]; + const mockColumns = [{ id: 'file', field: 'file', }, { id: 'size', field: 'size', }] as Column[]; + + jest.spyOn(dataviewStub, 'getItems').mockReturnValue(mockFlatDataset); + jest.spyOn(dataviewStub, 'getRowById').mockReturnValue(0); + jest.spyOn(treeDataServiceStub, 'convertFlatParentChildToTreeDatasetAndSort').mockReturnValue({ flat: mockFlatDataset as any[], hierarchical: mockHierarchical as any[] }); + jest.spyOn(gridStub, 'getOptions').mockReturnValue({ enableAutoResize: true, enableRowSelection: true, enableTreeData: true } as GridOption); + jest.spyOn(SharedService.prototype, 'allColumns', 'get').mockReturnValue(mockColumns); + const setItemSpy = jest.spyOn(dataviewStub, 'setItems'); + const updateSpy = jest.spyOn(dataviewStub, 'updateItem'); + const invalidateSpy = jest.spyOn(service, 'invalidateHierarchicalDataset'); + + service.updateItem(mockUpdatedItem); + + expect(updateSpy).toHaveBeenCalledTimes(1); + expect(updateSpy).toHaveBeenCalledWith(mockUpdatedItem.id, mockUpdatedItem); + expect(invalidateSpy).toHaveBeenCalled(); + expect(setItemSpy).toHaveBeenCalledWith(mockFlatDataset); + }); + + it('should invalidate and rerender the tree dataset when grid option "enableTreeData" is set when calling "updateItems"', () => { + const mockUpdatedItem = { id: 1, file: 'vacation.txt', size: 2.2, parentId: 0 }; + const mockFlatDataset = [{ id: 0, file: 'documents' }, { id: 1, file: 'vacation.txt', parentId: 0 }, mockUpdatedItem]; + const mockHierarchical = [{ id: 0, file: 'documents', files: [{ id: 1, file: 'vacation.txt' }, mockUpdatedItem] }]; + const mockColumns = [{ id: 'file', field: 'file', }, { id: 'size', field: 'size', }] as Column[]; + + jest.spyOn(dataviewStub, 'getItems').mockReturnValue(mockFlatDataset); + jest.spyOn(dataviewStub, 'getRowById').mockReturnValue(0); + jest.spyOn(treeDataServiceStub, 'convertFlatParentChildToTreeDatasetAndSort').mockReturnValue({ flat: mockFlatDataset as any[], hierarchical: mockHierarchical as any[] }); + jest.spyOn(gridStub, 'getOptions').mockReturnValue({ enableAutoResize: true, enableRowSelection: true, enableTreeData: true } as GridOption); + jest.spyOn(SharedService.prototype, 'allColumns', 'get').mockReturnValue(mockColumns); + const setItemSpy = jest.spyOn(dataviewStub, 'setItems'); + const updateSpy = jest.spyOn(dataviewStub, 'updateItems'); + const invalidateSpy = jest.spyOn(service, 'invalidateHierarchicalDataset'); + + service.updateItems([mockUpdatedItem]); + + expect(updateSpy).toHaveBeenCalledTimes(1); + expect(updateSpy).toHaveBeenCalledWith([mockUpdatedItem.id], [mockUpdatedItem]); + expect(invalidateSpy).toHaveBeenCalled(); + expect(setItemSpy).toHaveBeenCalledWith(mockFlatDataset); + }); }); describe('addItem methods', () => { diff --git a/src/app/modules/angular-slickgrid/services/grid.service.ts b/src/app/modules/angular-slickgrid/services/grid.service.ts index dcabd9776..a5ad3e858 100644 --- a/src/app/modules/angular-slickgrid/services/grid.service.ts +++ b/src/app/modules/angular-slickgrid/services/grid.service.ts @@ -777,6 +777,11 @@ export class GridService { // end the bulk transaction since we're all done this._dataView.endUpdate(); + if (this._gridOptions?.enableTreeData) { + // if we add/remove item(s) from the dataset, we need to also refresh our tree data filters + this.invalidateHierarchicalDataset(); + } + // only highlight at the end, all at once // we have to do this because doing highlight 1 by 1 would only re-select the last highlighted row which is wrong behavior if (options.highlightRow) { @@ -819,6 +824,11 @@ export class GridService { this._dataView.updateItem(itemId, item); this._grid.updateRow(rowNumber); + if (this._gridOptions?.enableTreeData) { + // if we add/remove item(s) from the dataset, we need to also refresh our tree data filters + this.invalidateHierarchicalDataset(); + } + // do we want to scroll to the row so that it shows in the Viewport (UI) if (options.scrollRowIntoView) { this._grid.scrollRowIntoView(rowNumber);