diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 3c940fa8e..da5a59463 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -1407,7 +1407,7 @@ describe('SlickGrid core file', () => { vi.spyOn(grid, 'getDataLength').mockReturnValueOnce(-1); grid.updateRowCount(); - expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(4); // 2x left and 2x right, because we have 2x columns + expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(2); // because we have 2x columns footerElms = container.querySelectorAll('.slick-footerrow'); expect(footerElms[0].style.display).not.toBe('none'); expect(footerElms[1].style.display).not.toBe('none'); @@ -1611,7 +1611,7 @@ describe('SlickGrid core file', () => { expect(grid.getRowCache()).toEqual({}); expect(onBeforeRemoveCachedRowSpy).toHaveBeenCalledTimes(4); - expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(4); // 2x left and 2x right, because we have 2x columns + expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(2); // because we have 2x columns footerElms = container.querySelectorAll('.slick-footerrow'); expect(footerElms[0].style.display).not.toBe('none'); expect(footerElms[1].style.display).not.toBe('none'); @@ -1643,7 +1643,7 @@ describe('SlickGrid core file', () => { grid.setFooterRowVisibility(true); grid.updateColumns(); // this will trigger onBeforeFooterRowCellDestroySpy - expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(4); // 2x left and 2x right, because we have 2x columns + expect(onBeforeFooterRowCellDestroySpy).toHaveBeenCalledTimes(2); // because we have 2x columns footerElms = container.querySelectorAll('.slick-footerrow'); expect(footerElms[0].style.display).not.toBe('none'); expect(footerElms[1].style.display).not.toBe('none'); diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index 46c31047d..1e031e926 100755 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -1671,6 +1671,8 @@ export class SlickGrid = Column, O e /** Get the Footer DOM element */ getFooterRow(): HTMLDivElement | HTMLDivElement[] { + // return undefined consistently when there is no footer, instead of throwing on + // the non-frozen `_footerRow[0]` path while the frozen path returns undefined return this.hasFrozenColumns() ? this._footerRow : this._footerRow?.[0]; } @@ -1831,35 +1833,11 @@ export class SlickGrid = Column, O e emptyElement(this._headerRowL); emptyElement(this._headerRowR); - if (this._options.createFooterRow) { - const footerRowLColumnElements = this._footerRowL.querySelectorAll('.slick-footerrow-column'); - footerRowLColumnElements.forEach((column) => { - const columnDef = Utils.storage.get(column, 'column'); - if (columnDef) { - this.triggerEvent(this.onBeforeFooterRowCellDestroy, { - node: this, - column: columnDef, - grid: this, - }); - } - }); - emptyElement(this._footerRowL); - - if (this.hasFrozenColumns()) { - const footerRowRColumnElements = this._footerRowR.querySelectorAll('.slick-footerrow-column'); - footerRowRColumnElements.forEach((column) => { - const columnDef = Utils.storage.get(column, 'column'); - if (columnDef) { - this.triggerEvent(this.onBeforeFooterRowCellDestroy, { - node: this, - column: columnDef, - grid: this, - }); - } - }); - emptyElement(this._footerRowR); - } - } + // NOTE: footer-row destroy/create is handled entirely by createColumnFooter(), + // which is always called immediately after createColumnHeaders(). The duplicate + // footer blocks that used to live here fired onFooterRowCellRendered twice per + // column and emptied the right footer only under hasFrozenColumns() (leaving + // stale right-footer cells after un-freezing). for (let i = 0, ln = this.columns.length; i < ln; i++) { const m: C = this.columns[i]; @@ -1987,25 +1965,8 @@ export class SlickGrid = Column, O e grid: this, }); } - if (this._options.createFooterRow && this._options.showFooterRow) { - const footerRowTarget = this.hasFrozenColumns() - ? i <= this._options.frozenColumn! - ? this._footerRow[0] - : this._footerRow[1] - : this._footerRow[0]; - const footerRowCell = createDomElement( - 'div', - { className: `slick-state-default slick-footerrow-column l${i} r${i}` }, - footerRowTarget - ); - Utils.storage.put(footerRowCell, 'column', m); - this.triggerEvent(this.onFooterRowCellRendered, { - node: footerRowCell, - column: m, - grid: this, - }); - } + // footer-row cells are created by createColumnFooter() (called right after), not here } this.setSortColumns(this.sortColumns); @@ -4894,7 +4855,10 @@ export class SlickGrid = Column, O e if (!this._options.autoHeight || this._options.frozenColumn !== -1) { this.topPanelH = this._options.showTopPanel ? this._options.topPanelHeight! + this.getVBoxDelta(this._topPanelScrollers[0]) : 0; this.headerRowH = this._options.showHeaderRow ? this._options.headerRowHeight! + this.getVBoxDelta(this._headerRowScroller[0]) : 0; - this.footerRowH = this._options.showFooterRow ? this._options.footerRowHeight! + this.getVBoxDelta(this._footerRowScroller[0]) : 0; + this.footerRowH = + this._options.createFooterRow && this._options.showFooterRow + ? this._options.footerRowHeight! + this.getVBoxDelta(this._footerRowScroller[0]) + : 0; } if (this._options.autoHeight) { @@ -4903,7 +4867,10 @@ export class SlickGrid = Column, O e ? this._options.preHeaderPanelHeight! + this.getVBoxDelta(this._preHeaderPanelScroller) : 0; fullHeight += this._options.showHeaderRow ? this._options.headerRowHeight! + this.getVBoxDelta(this._headerRowScroller[0]) : 0; - fullHeight += this._options.showFooterRow ? this._options.footerRowHeight! + this.getVBoxDelta(this._footerRowScroller[0]) : 0; + fullHeight += + this._options.createFooterRow && this._options.showFooterRow + ? this._options.footerRowHeight! + this.getVBoxDelta(this._footerRowScroller[0]) + : 0; fullHeight += this.getCanvasWidth() > this.viewportW ? this.scrollbarDimensions?.height || 0 : 0; this.viewportH = this.getRowPosition(this.getDataLengthIncludingAddNew()) + (this._options.frozenColumn === -1 ? fullHeight : 0);