diff --git a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts index 00dcd6cda..a4200a81c 100644 --- a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts +++ b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts @@ -686,6 +686,17 @@ describe('Angular-Slickgrid Custom Component instantiated via Constructor', () = expect(syncSpy).toHaveBeenCalledWith(component.grid, false); }); + it('should destroy customElement and its DOM element when requested', () => { + const spy = jest.spyOn(component, 'emptyGridContainerElm'); + + component.gridOptions = { enableFiltering: true } as GridOption; + component.ngAfterViewInit(); + component.destroy(true); + + expect(spy).toHaveBeenCalledWith(); + }); + + it('should bind local filter when "enableFiltering" is set', () => { const bindLocalSpy = jest.spyOn(filterServiceStub, 'bindLocalOnFilter'); diff --git a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts index 50b1603f0..4c01e5abf 100644 --- a/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts +++ b/src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid.component.spec.ts @@ -313,7 +313,7 @@ describe('App Component', () => { const mockDataset = [{ id: 1, firstName: 'John' }, { id: 2, firstName: 'Jane' }]; component.gridId = 'grid1'; - component.gridOptions = { enablePagination: false, showCustomFooter: true, autoFitColumnsOnFirstLoad: false, enableAutoSizeColumns: false, enableAutoResizeColumnsByCellContent: true } as GridOption; + component.gridOptions = { enablePagination: false, resizeByContentOnlyOnFirstLoad: false, showCustomFooter: true, autoFitColumnsOnFirstLoad: false, enableAutoSizeColumns: false, enableAutoResizeColumnsByCellContent: true } as GridOption; component.dataset = mockDataset; fixture.detectChanges(); component.dataView.onSetItemsCalled.notify({ idProperty: 'id', itemCount: 1 }); @@ -323,111 +323,127 @@ describe('App Component', () => { done(); }, 10); }); - }); - describe('Custom Footer', () => { - it('should display 1 items selected on the left side footer section after triggering "onSelectedRowsChanged" event', () => { - const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; + it('should call "resizeColumnsByCellContent" when the DataView "onSetItemsCalled" event is triggered and "enableAutoResizeColumnsByCellContent" is set', (done) => { + const resizeContentSpy = jest.spyOn(resizerServiceStub, 'resizeColumnsByCellContent'); + const mockDataset = [{ id: 1, firstName: 'John' }, { id: 2, firstName: 'Jane' }]; component.gridId = 'grid1'; - component.gridOptions = { - enablePagination: false, - showCustomFooter: true, - enableCheckboxSelector: true, - customFooterOptions: { - hideRowSelectionCount: false - } - } as GridOption; - fixture.detectChanges(); - component.columnDefinitions = mockColDefs; - component.grid.setSelectionModel(new Slick.CellSelectionModel()); - component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); - fixture.detectChanges(); - - const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; - const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; - const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; - const leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; - const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; - - expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); - expect(gridContainerElm.id).toBe('grid1'); - expect(footerContainerElm).toBeTruthy(); - expect(rightFooterElm).toBeTruthy(); - expect(leftFooterElm).toBeTruthy(); - expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('1 items selected'); - expect(leftFooterElm.innerHTML).toContain('1 items selected'); - }); - - it('should display row selection count in French on the left side footer section after triggering "onSelectedRowsChanged" event when using "fr" as locale', () => { - const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; - - translate.use('fr'); - component.gridOptions = { - enablePagination: false, - enableTranslate: true, - showCustomFooter: true, - enableCheckboxSelector: true, - } as GridOption; - fixture.detectChanges(); - component.columnDefinitions = mockColDefs; - component.grid.setSelectionModel(new Slick.CellSelectionModel()); - component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); - fixture.detectChanges(); - - const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; - const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; - const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; - let leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; - const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; - - expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); - expect(gridContainerElm.id).toBe('grid1'); - expect(footerContainerElm).toBeTruthy(); - expect(rightFooterElm).toBeTruthy(); - expect(leftFooterElm).toBeTruthy(); - expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('1 éléments sélectionnés'); - expect(leftFooterElm.innerHTML).toContain('1 éléments sélectionnés'); - - component.grid.onSelectedRowsChanged.notify({ rows: [1, 2, 3, 4, 5], previousSelectedRows: [] }); + component.gridOptions = { enablePagination: false, resizeByContentOnlyOnFirstLoad: true, showCustomFooter: true, autoFitColumnsOnFirstLoad: false, enableAutoSizeColumns: false, enableAutoResizeColumnsByCellContent: true } as GridOption; + component.dataset = mockDataset; fixture.detectChanges(); - leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; + component.dataView.onSetItemsCalled.notify({ idProperty: 'id', itemCount: 1 }); - expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('5 éléments sélectionnés'); - expect(leftFooterElm.innerHTML).toContain('5 éléments sélectionnés'); + setTimeout(() => { + expect(resizeContentSpy).toHaveBeenCalledWith(false); + done(); + }, 10); }); - it('should not not display row selection count after triggering "onSelectedRowsChanged" event when "hideRowSelectionCount" is set to True', () => { - const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; - - component.gridId = 'grid1'; - component.gridOptions = { - enablePagination: false, - showCustomFooter: true, - enableCheckboxSelector: true, - customFooterOptions: { - hideRowSelectionCount: true - } - } as GridOption; - fixture.detectChanges(); - component.columnDefinitions = mockColDefs; - component.grid.setSelectionModel(new Slick.CellSelectionModel()); - component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); - fixture.detectChanges(); - - const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; - const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; - const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; - const leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; - const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; - - expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); - expect(gridContainerElm.id).toBe('grid1'); - expect(footerContainerElm).toBeTruthy(); - expect(rightFooterElm).toBeTruthy(); - expect(leftFooterElm).toBeTruthy(); - expect(component.gridOptions.customFooterOptions!.leftFooterText).toBeFalsy(); - expect(leftFooterElm.innerHTML).toBeFalsy(); + describe('Custom Footer', () => { + it('should display 1 items selected on the left side footer section after triggering "onSelectedRowsChanged" event', () => { + const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; + + component.gridId = 'grid1'; + component.gridOptions = { + enablePagination: false, + showCustomFooter: true, + enableCheckboxSelector: true, + customFooterOptions: { + hideRowSelectionCount: false + } + } as GridOption; + fixture.detectChanges(); + component.columnDefinitions = mockColDefs; + component.grid.setSelectionModel(new Slick.CellSelectionModel()); + component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); + fixture.detectChanges(); + + const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; + const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; + const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; + const leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; + const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; + + expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); + expect(gridContainerElm.id).toBe('grid1'); + expect(footerContainerElm).toBeTruthy(); + expect(rightFooterElm).toBeTruthy(); + expect(leftFooterElm).toBeTruthy(); + expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('1 items selected'); + expect(leftFooterElm.innerHTML).toContain('1 items selected'); + }); + + it('should display row selection count in French on the left side footer section after triggering "onSelectedRowsChanged" event when using "fr" as locale', () => { + const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; + + translate.use('fr'); + component.gridOptions = { + enablePagination: false, + enableTranslate: true, + showCustomFooter: true, + enableCheckboxSelector: true, + } as GridOption; + fixture.detectChanges(); + component.columnDefinitions = mockColDefs; + component.grid.setSelectionModel(new Slick.CellSelectionModel()); + component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); + fixture.detectChanges(); + + const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; + const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; + const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; + let leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; + const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; + + expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); + expect(gridContainerElm.id).toBe('grid1'); + expect(footerContainerElm).toBeTruthy(); + expect(rightFooterElm).toBeTruthy(); + expect(leftFooterElm).toBeTruthy(); + expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('1 éléments sélectionnés'); + expect(leftFooterElm.innerHTML).toContain('1 éléments sélectionnés'); + + component.grid.onSelectedRowsChanged.notify({ rows: [1, 2, 3, 4, 5], previousSelectedRows: [] }); + fixture.detectChanges(); + leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; + + expect(component.gridOptions.customFooterOptions!.leftFooterText).toBe('5 éléments sélectionnés'); + expect(leftFooterElm.innerHTML).toContain('5 éléments sélectionnés'); + }); + + it('should not not display row selection count after triggering "onSelectedRowsChanged" event when "hideRowSelectionCount" is set to True', () => { + const mockColDefs = [{ id: 'name', field: 'name', editor: undefined, internalColumnEditor: {} }]; + + component.gridId = 'grid1'; + component.gridOptions = { + enablePagination: false, + showCustomFooter: true, + enableCheckboxSelector: true, + customFooterOptions: { + hideRowSelectionCount: true + } + } as GridOption; + fixture.detectChanges(); + component.columnDefinitions = mockColDefs; + component.grid.setSelectionModel(new Slick.CellSelectionModel()); + component.grid.onSelectedRowsChanged.notify({ rows: [1], previousSelectedRows: [] }); + fixture.detectChanges(); + + const gridContainerElm = document.querySelector('.slickgrid-container') as HTMLDivElement; + const gridPaneElm = document.querySelector('.gridPane') as HTMLDivElement; + const footerContainerElm = document.querySelector('div.slick-custom-footer') as HTMLDivElement; + const leftFooterElm = document.querySelector('div.slick-custom-footer > div.left-footer') as HTMLSpanElement; + const rightFooterElm = document.querySelector('div.slick-custom-footer > div.metrics') as HTMLSpanElement; + + expect(gridPaneElm.id).toBe('slickGridContainer-grid1'); + expect(gridContainerElm.id).toBe('grid1'); + expect(footerContainerElm).toBeTruthy(); + expect(rightFooterElm).toBeTruthy(); + expect(leftFooterElm).toBeTruthy(); + expect(component.gridOptions.customFooterOptions!.leftFooterText).toBeFalsy(); + expect(leftFooterElm.innerHTML).toBeFalsy(); + }); }); }); }); diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts index 277961c4a..02f743121 100644 --- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts @@ -15,7 +15,7 @@ import { isObservable, Observable, Subscription } from 'rxjs'; import { Constants } from '../constants'; import { GlobalGridOptions } from './../global-grid-options'; -import { convertParentChildArrayToHierarchicalView, titleCase, unsubscribeAllObservables } from './../services/utilities'; +import { emptyElement, titleCase, unsubscribeAllObservables } from './../services/utilities'; import { executeBackendProcessesCallback, onBackendError, refreshBackendDataset } from '../services/backend-utilities'; import { AngularGridInstance, @@ -368,8 +368,9 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn } emptyGridContainerElm() { - const gridContainerId = this.gridOptions && this.gridOptions.gridContainerId || 'grid1'; - $(gridContainerId).empty(); + const gridContainerId = this.gridOptions?.gridContainerId ?? 'grid1'; + const gridContainerElm = document.querySelector(gridContainerId); + emptyElement(gridContainerElm); } /** Dispatch of Custom Event, which by default will bubble & is cancelable */ @@ -658,7 +659,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn if (args.itemCount > 0 && (this.gridOptions.autosizeColumnsByCellContentOnFirstLoad || this.gridOptions.enableAutoResizeColumnsByCellContent)) { // add a delay so that if column positions changes by changeColumnsArrangement() when using custom Grid Views // or presets.columns won't have any impact on the list of visible columns and their positions - setTimeout(() => this.resizer.resizeColumnsByCellContent(true), 10); + setTimeout(() => this.resizer.resizeColumnsByCellContent(!this.gridOptions?.resizeByContentOnlyOnFirstLoad), 10); } }); diff --git a/src/app/modules/angular-slickgrid/global-grid-options.ts b/src/app/modules/angular-slickgrid/global-grid-options.ts index f1c32b93d..b5690ef69 100644 --- a/src/app/modules/angular-slickgrid/global-grid-options.ts +++ b/src/app/modules/angular-slickgrid/global-grid-options.ts @@ -209,6 +209,7 @@ export const GlobalGridOptions: Partial = { rowHeight: 35, topPanelHeight: 35, translationNamespaceSeparator: ':', + resizeByContentOnlyOnFirstLoad: true, resizeAlwaysRecalculateColumnWidth: false, resizeCellCharWidthInPx: 7.8, resizeCellPaddingWidthInPx: 14, diff --git a/src/app/modules/angular-slickgrid/models/gridOption.interface.ts b/src/app/modules/angular-slickgrid/models/gridOption.interface.ts index a72d2a456..974eb2b4c 100644 --- a/src/app/modules/angular-slickgrid/models/gridOption.interface.ts +++ b/src/app/modules/angular-slickgrid/models/gridOption.interface.ts @@ -438,19 +438,27 @@ export interface GridOption { /** defaults to false, if a column `width` is provided (or was previously calculated) should we recalculate it or not when resizing by cell content? */ resizeAlwaysRecalculateColumnWidth?: boolean; + /** + * defaults to true, do we want to resize the grid by content only on the first page or anytime the data changes? + * Requires `enableAutoResizeColumnsByCellContent` to be set. + * Also don't get confused with `autosizeColumnsByCellContentOnFirstLoad` that flag won't block resize by content after the first load while `resizeByContentOnlyOnFirstLoad` + */ + resizeByContentOnlyOnFirstLoad?: boolean; + /** * Defaults to 7, width in pixels of a string character which is used by the resize columns by its content, this can vary depending on which font family/size is used & cell padding. * This is only used when resizing the columns width by their content, we need to know the width of a character in pixel to do all calculations. + * Requires `enableAutoResizeColumnsByCellContent` to be set. */ resizeCellCharWidthInPx?: number; - /** Defaults to 6, cell padding width to add to the calculation when resizing columns by their cell text content. */ + /** Defaults to 6, cell padding width to add to the calculation when resizing columns by their cell text content (requires `enableAutoResizeColumnsByCellContent` to be set) */ resizeCellPaddingWidthInPx?: number; - /** Defaults to around ~0.9, what is the ratio to use (on field `type` "string" only) in the calculation when resizing columns by their cell text content. */ + /** Defaults to around ~0.9, what is the ratio to use (on field `type` "string" only) in the calculation when resizing columns by their cell text content (requires `enableAutoResizeColumnsByCellContent` to be set). */ resizeDefaultRatioForStringType?: number; - /** Defaults to 6, padding width to add to the calculation when using a Formatter and resizing columns by their cell text content. */ + /** Defaults to 6, padding width to add to the calculation when using a Formatter and resizing columns by their cell text content (requires `enableAutoResizeColumnsByCellContent` to be set). */ resizeFormatterPaddingWidthInPx?: number; /** diff --git a/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts index d26070434..ea6c4672f 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts @@ -10,6 +10,7 @@ import { convertParentChildArrayToHierarchicalView, decimalFormatted, deepCopy, + emptyElement, findItemInHierarchicalStructure, findOrDefault, formatNumber, @@ -96,7 +97,7 @@ describe('Service/Utilies', () => { }); it('should use jQuery and return a decoded HTML string with single quotes encoded as well when DOMParser is not available in older browser', () => { - DOMParser = undefined; + DOMParser = undefined as any; const result = htmlDecode(`<div class='color: blue'>Something</div>`); expect(result).toBe(`
Something
`); }); @@ -204,7 +205,7 @@ describe('Service/Utilies', () => { }); describe('convertHierarchicalViewToParentChildArray method', () => { - let mockColumns; + let mockColumns: any[]; beforeEach(() => { mockColumns = [ @@ -235,7 +236,7 @@ describe('Service/Utilies', () => { }); describe('findItemInHierarchicalStructure method', () => { - let mockColumns; + let mockColumns: any[]; beforeEach(() => { mockColumns = [ @@ -268,7 +269,7 @@ describe('Service/Utilies', () => { describe('castToPromise method', () => { it('should throw an error when argument provided is not a Promise neither an Observable', async () => { - expect(() => castToPromise(null)).toThrowError('Something went wrong,'); + expect(() => castToPromise(null as any)).toThrowError('Something went wrong,'); }); it('should return original Promise when argument is already a Promise', async () => { @@ -414,6 +415,18 @@ describe('Service/Utilies', () => { }); }); + describe('emptyElement method', () => { + const div = document.createElement('div'); + div.innerHTML = ``; + document.body.appendChild(div); + + it('should empty the DOM element', () => { + expect(div.outerHTML).toBe('
'); + emptyElement(div); + expect(div.outerHTML).toBe('
'); + }); + }); + describe('formatNumber method', () => { it('should return original value when input provided is not a number', () => { const input = 'abc'; @@ -460,7 +473,7 @@ describe('Service/Utilies', () => { it('should return a string without decimals when these arguments are null or undefined and the input provided is an integer', () => { const input = 12345678; const output1 = formatNumber(input); - const output2 = formatNumber(input, null, null); + const output2 = formatNumber(input, null as any, null as any); const output3 = formatNumber(input, undefined, undefined); expect(output1).toBe('12345678'); @@ -472,7 +485,7 @@ describe('Service/Utilies', () => { const input = 12345678; const decimalSeparator = '.'; const thousandSeparator = ','; - const output1 = formatNumber(input, null, null, false, '', '', decimalSeparator, thousandSeparator); + const output1 = formatNumber(input, null as any, null as any, false, '', '', decimalSeparator, thousandSeparator); const output2 = formatNumber(input, undefined, undefined, false, '', '', decimalSeparator, thousandSeparator); expect(output1).toBe('12,345,678'); @@ -483,7 +496,7 @@ describe('Service/Utilies', () => { const input = 12345678; const decimalSeparator = ','; const thousandSeparator = '.'; - const output1 = formatNumber(input, null, null, false, '', '', decimalSeparator, thousandSeparator); + const output1 = formatNumber(input, null as any, null as any, false, '', '', decimalSeparator, thousandSeparator); const output2 = formatNumber(input, undefined, undefined, false, '', '', decimalSeparator, thousandSeparator); expect(output1).toBe('12.345.678'); @@ -559,7 +572,7 @@ describe('Service/Utilies', () => { const displayNegativeNumberWithParentheses = true; const currencyPrefix = '$'; const currencySuffix = ' CAD'; - const output = formatNumber(input, null, null, displayNegativeNumberWithParentheses, currencyPrefix, currencySuffix); + const output = formatNumber(input, null as any, null as any, displayNegativeNumberWithParentheses, currencyPrefix, currencySuffix); expect(output).toBe('($1234 CAD)'); }); @@ -570,7 +583,7 @@ describe('Service/Utilies', () => { const currencySuffix = ' CAD'; const decimalSeparator = ','; const thousandSeparator = '_'; - const output = formatNumber(input, null, null, displayNegativeNumberWithParentheses, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); + const output = formatNumber(input, null as any, null as any, displayNegativeNumberWithParentheses, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); expect(output).toBe('($12_345_678 CAD)'); }); }); @@ -609,7 +622,7 @@ describe('Service/Utilies', () => { it('should return the object descendant even when path given is not a dot notation', () => { const output = getDescendantProperty(obj, 'user'); - expect(output).toEqual(obj['user']); + expect(output).toEqual((obj as any)['user']); }); it('should return the object descendant when using dot notation', () => { @@ -625,7 +638,7 @@ describe('Service/Utilies', () => { describe('getTranslationPrefix method', () => { it('should return empty Translation Prefix when no Grid Options are provided', () => { - const output = getTranslationPrefix(null); + const output = getTranslationPrefix(null as any); expect(output).toBe(''); }); @@ -1253,17 +1266,17 @@ describe('Service/Utilies', () => { it('should be able to update an object at 2nd level deep property', () => { setDeepValue(obj, 'user.firstName', 'Jane'); - expect(obj['user'].firstName).toBe('Jane'); + expect((obj as any)['user'].firstName).toBe('Jane'); }); it('should be able to update an object at 3rd level deep property', () => { setDeepValue(obj, 'user.address.number', 78); - expect(obj['user']['address']['number']).toBe(78); + expect((obj as any)['user']['address']['number']).toBe(78); }); it('should be able to update a property that is not a complex object', () => { setDeepValue(obj, 'id', 76); - expect(obj['id']).toBe(76); + expect((obj as any)['id']).toBe(76); }); }); @@ -1276,7 +1289,7 @@ describe('Service/Utilies', () => { it('should return original value when input provided is undefined', () => { const input = undefined; - const output = thousandSeparatorFormatted(input, ','); + const output = thousandSeparatorFormatted(input as any, ','); expect(output).toBe(input); }); @@ -1315,7 +1328,7 @@ describe('Service/Utilies', () => { it('should return empty string when input is null', () => { const input = null; - const output = titleCase(input); + const output = titleCase(input as any); expect(output).toBe(null); }); @@ -1341,7 +1354,7 @@ describe('Service/Utilies', () => { it('should return empty string when input is null', () => { const input = null; - const output = toCamelCase(input); + const output = toCamelCase(input as any); expect(output).toBe(null); }); @@ -1366,7 +1379,7 @@ describe('Service/Utilies', () => { it('should return empty string when input is null', () => { const input = null; - const output = toKebabCase(input); + const output = toKebabCase(input as any); expect(output).toBe(null); }); @@ -1391,7 +1404,7 @@ describe('Service/Utilies', () => { it('should return empty string when input is null', () => { const input = null; - const output = toSnakeCase(input); + const output = toSnakeCase(input as any); expect(output).toBe(null); }); @@ -1408,8 +1421,8 @@ describe('Service/Utilies', () => { describe('uniqueArray method', () => { it('should return original value when input is not an array', () => { - const output1 = uniqueArray(null); - const output2 = uniqueArray(undefined); + const output1 = uniqueArray(null as any); + const output2 = uniqueArray(undefined as any); expect(output1).toBeNull(); expect(output2).toBe(undefined); @@ -1433,8 +1446,8 @@ describe('Service/Utilies', () => { describe('uniqueObjectArray method', () => { it('should return original value when input is not an array', () => { - const output1 = uniqueObjectArray(null); - const output2 = uniqueObjectArray(undefined); + const output1 = uniqueObjectArray(null as any); + const output2 = uniqueObjectArray(undefined as any); expect(output1).toBeNull(); expect(output2).toBe(undefined); diff --git a/src/app/modules/angular-slickgrid/services/resizer.service.ts b/src/app/modules/angular-slickgrid/services/resizer.service.ts index 3ded5db47..9c5f1a56c 100644 --- a/src/app/modules/angular-slickgrid/services/resizer.service.ts +++ b/src/app/modules/angular-slickgrid/services/resizer.service.ts @@ -28,6 +28,7 @@ export class ResizerService { private _grid: any; private _gridDomElm: any; private _gridContainerElm: any; + private _hasResizedByContentAtLeastOnce = false; private _lastDimensions: GridDimension | undefined; private _totalColumnsWidthByContent = 0; private _timer: any; @@ -271,7 +272,7 @@ export class ResizerService { const columnWidths: { [columnId in string | number]: number; } = {}; let reRender = false; - if (!Array.isArray(dataset) || dataset.length === 0) { + if ((!Array.isArray(dataset) || dataset.length === 0) || (this._hasResizedByContentAtLeastOnce && this._gridOptions?.resizeByContentOnlyOnFirstLoad && !recalculateColumnsTotalWidth)) { return; } @@ -368,6 +369,7 @@ export class ResizerService { // send updated column definitions widths to SlickGrid this._grid.setColumns(columnDefinitions); + this._hasResizedByContentAtLeastOnce = true; // get the grid container viewport width and if our viewport calculated total columns is greater than the viewport width // then we'll call reRenderColumns() when getting wider than viewport or else the default autosizeColumns() when we know we have plenty of space to shrink the columns diff --git a/src/app/modules/angular-slickgrid/services/utilities.ts b/src/app/modules/angular-slickgrid/services/utilities.ts index af59bd9d0..44ca44d4e 100644 --- a/src/app/modules/angular-slickgrid/services/utilities.ts +++ b/src/app/modules/angular-slickgrid/services/utilities.ts @@ -193,6 +193,21 @@ export function deepCopy(obj: any) { return obj; } +/** + * Empty a DOM element by removing all of its DOM element children leaving with an empty element (basically an empty shell) + * @return {object} element - updated element + */ +export function emptyElement(element?: T | null): T | undefined | null { + if (element?.firstChild) { + while (element.firstChild) { + if (element.lastChild) { + element.removeChild(element.lastChild); + } + } + } + return element; +} + /** * Find an item from a hierarchical view structure (a parent that can have children array which themseleves can children and so on) * @param hierarchicalArray