From 7f650c98dff61bb5e3e7eb3255f2889bab04be7e Mon Sep 17 00:00:00 2001 From: Martin Dragnev <37667452+mddragnev@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:04:24 +0200 Subject: [PATCH] fix(columns): Change how column width is parsed - 19.0.x (#14991) --- .../grids/columns/column-group.component.ts | 2 +- .../grids/columns/column-layout.component.ts | 4 +-- .../src/lib/grids/columns/column.component.ts | 12 ++++----- .../src/lib/grids/grid-base.directive.ts | 14 +++++------ .../src/lib/grids/grid/column-group.spec.ts | 22 ++++++++-------- .../grids/grid/grid.multi-row-layout.spec.ts | 25 +++++++++++-------- .../src/lib/grids/headers/pipes.ts | 2 +- .../src/lib/test-utils/grid-functions.spec.ts | 2 +- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/columns/column-group.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column-group.component.ts index 0dc61063adf..e3fb71534c7 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column-group.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column-group.component.ts @@ -388,7 +388,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After if (val.hidden) { return acc; } - return acc + parseInt(val.calcWidth, 10); + return acc + parseFloat(val.calcWidth); }, 0)}`; return width + 'px'; } diff --git a/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts index 2580d4f927a..202b87382e5 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts @@ -43,7 +43,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements * @memberof IgxColumnGroupComponent */ public override get width(): any { - const width = this.getFilledChildColumnSizes(this.children).reduce((acc, val) => acc + parseInt(val, 10), 0); + const width = this.getFilledChildColumnSizes(this.children).reduce((acc, val) => acc + parseFloat(val), 0); return width; } @@ -62,7 +62,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements if (this.headerGroup && this.headerGroup.hasLastPinnedChildColumn) { const headerStyles = this.grid.document.defaultView.getComputedStyle(this.headerGroup.nativeElement.children[0]); - borderWidth = parseInt(headerStyles.borderRightWidth, 10); + borderWidth = parseFloat(headerStyles.borderRightWidth); } return super.getCalcWidth() + borderWidth; diff --git a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts index 0f05119cecc..7b23feeddfd 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts @@ -1984,7 +1984,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy columnSizes[col.colStart - 1] = { ref: col, width: col.width === 'fit-content' ? col.autoSize : - col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null, + col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null, colSpan: col.gridColumnSpan, colEnd: col.colStart + col.gridColumnSpan, widthSetByUser: col.widthSetByUser @@ -2013,7 +2013,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy columnSizes[col.colStart - 1] = { ref: col, width: col.width === 'fit-content' ? col.autoSize : - col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null, + col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null, colSpan: col.gridColumnSpan, colEnd: col.colStart + col.gridColumnSpan, widthSetByUser: col.widthSetByUser @@ -2027,7 +2027,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy columnSizes[i] = { ref: col, width: col.width === 'fit-content' ? col.autoSize : - col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null, + col.widthSetByUser || this.grid.columnWidthSetByUser ? parseFloat(col.calcWidth) : null, colSpan: col.gridColumnSpan, colEnd: col.colStart + col.gridColumnSpan, widthSetByUser: col.widthSetByUser @@ -2091,7 +2091,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy if (size && !!size.width) { result.push(size.width + 'px'); } else { - result.push(parseInt(this.grid.getPossibleColumnWidth(), 10) + 'px'); + result.push(parseFloat(this.grid.getPossibleColumnWidth()) + 'px'); } } return result; @@ -2561,14 +2561,14 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy if (isPercentageWidth && this.grid.isColumnWidthSum) { this._calcWidth = this.grid.minColumnWidth; } else if (isPercentageWidth ) { - this._calcWidth = Math.floor(parseFloat(colWidth) / 100 * this.grid.calcWidth); + this._calcWidth = parseFloat(colWidth) / 100 * this.grid.calcWidth; } else if (!colWidth || isAutoWidth && !this.autoSize) { // no width this._calcWidth = this.defaultWidth || this.grid.getPossibleColumnWidth(); } else { this._calcWidth = this.width; } - this.calcPixelWidth = parseInt(this._calcWidth, 10); + this.calcPixelWidth = parseFloat(this._calcWidth); } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 585eaf12af2..1748221c6b5 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -4554,7 +4554,7 @@ export abstract class IgxGridBaseDirective implements GridType, let totalWidth = 0; let i = 0; for (i; i < cols.length; i++) { - totalWidth += parseInt(cols[i].calcWidth, 10) || 0; + totalWidth += parseFloat(cols[i].calcWidth) || 0; } this._totalWidth = totalWidth; return totalWidth; @@ -5400,7 +5400,7 @@ export abstract class IgxGridBaseDirective implements GridType, computedWidth = baseWidth; } else { computedWidth = this.calcWidth || - parseInt(this.document.defaultView.getComputedStyle(this.nativeElement).getPropertyValue('width'), 10); + parseFloat(this.document.defaultView.getComputedStyle(this.nativeElement).getPropertyValue('width')); } const visibleChildColumns = this.visibleColumns.filter(c => !c.columnGroup); @@ -5424,7 +5424,7 @@ export abstract class IgxGridBaseDirective implements GridType, const sumExistingWidths = columnsWithSetWidths .reduce((prev, curr) => { const colWidth = curr.width; - let widthValue = parseInt(colWidth, 10); + let widthValue = parseFloat(colWidth); if (isNaN(widthValue)) { widthValue = MINIMUM_COLUMN_WIDTH; } @@ -5440,9 +5440,9 @@ export abstract class IgxGridBaseDirective implements GridType, } computedWidth -= this.featureColumnsWidth(); - const columnWidth = Math.floor(!Number.isFinite(sumExistingWidths) ? + const columnWidth = !Number.isFinite(sumExistingWidths) ? Math.max(computedWidth / columnsToSize, this.minColumnWidth) : - Math.max((computedWidth - sumExistingWidths) / columnsToSize, this.minColumnWidth)); + Math.max((computedWidth - sumExistingWidths) / columnsToSize, this.minColumnWidth); return columnWidth + 'px'; } @@ -6526,8 +6526,8 @@ export abstract class IgxGridBaseDirective implements GridType, this._columnWidth = this.width !== null ? this.getPossibleColumnWidth() : this.minColumnWidth + 'px'; } this._columns.forEach((column: IgxColumnComponent) => { - if (this.hasColumnLayouts && parseInt(this._columnWidth, 10)) { - const columnWidthCombined = parseInt(this._columnWidth, 10) * (column.colEnd ? column.colEnd - column.colStart : 1); + if (this.hasColumnLayouts && parseFloat(this._columnWidth)) { + const columnWidthCombined = parseFloat(this._columnWidth) * (column.colEnd ? column.colEnd - column.colStart : 1); column.defaultWidth = columnWidthCombined + 'px'; } else { // D.K. March 29th, 2021 #9145 Consider min/max width when setting defaultWidth property diff --git a/projects/igniteui-angular/src/lib/grids/grid/column-group.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/column-group.spec.ts index 8a18192c7ba..fd9c04de40f 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/column-group.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/column-group.spec.ts @@ -551,10 +551,10 @@ describe('IgxGrid - multi-column headers #grid', () => { fixture.detectChanges(); const scrWitdh = grid.nativeElement.querySelector('.igx-grid__tbody-scrollbar').getBoundingClientRect().width; const gridWidthInPx = parseInt(gridWidth, 10) - scrWitdh; - const colWidth = Math.floor(gridWidthInPx / 3); + const colWidth = gridWidthInPx / 3; const colWidthPx = colWidth + 'px'; const locationColGroup = getColGroup(grid, 'Location'); - expect(locationColGroup.width).toBe((Math.round(colWidth) * 3) + 'px'); + expect(locationColGroup.width).toBe(colWidth * 3 + 'px'); const countryColumn = grid.getColumnByName('Country'); expect(countryColumn.width).toBe(colWidthPx); const regionColumn = grid.getColumnByName('Region'); @@ -576,7 +576,7 @@ describe('IgxGrid - multi-column headers #grid', () => { // check group has correct size. let locationColGroup = getColGroup(grid, 'Location'); - let expectedWidth = (200 + Math.floor(grid.calcWidth * 0.7)) + 'px'; + let expectedWidth = (200 + grid.calcWidth * 0.7) + 'px'; expect(locationColGroup.width).toBe(expectedWidth); // check header and content have same size. @@ -600,7 +600,7 @@ describe('IgxGrid - multi-column headers #grid', () => { fixture.detectChanges(); locationColGroup = getColGroup(grid, 'Location'); - expectedWidth = (200 + Math.floor(grid.calcWidth * 0.7)) + 'px'; + expectedWidth = (200 + grid.calcWidth * 0.7) + 'px'; expect(locationColGroup.width).toBe(expectedWidth); col2Header = grid.getColumnByName('Region').headerCell.nativeElement; @@ -625,7 +625,7 @@ describe('IgxGrid - multi-column headers #grid', () => { // check group has correct size. Should fill available space in grid since one column has no width. const locationColGroup = getColGroup(grid, 'Location'); - const expectedWidth = grid.calcWidth - 1 + 'px'; + const expectedWidth = grid.calcWidth + 'px'; expect(locationColGroup.width).toBe(expectedWidth); // check header and content have same size. @@ -651,10 +651,10 @@ describe('IgxGrid - multi-column headers #grid', () => { const gridWidthInPx = (parseInt(gridWidth, 10) / 100) * parseInt(componentInstance.gridWrapperWidthPx, 10) - scrWitdh; - const colWidth = Math.floor(gridWidthInPx / 3); + const colWidth = gridWidthInPx / 3; const colWidthPx = colWidth + 'px'; const locationColGroup = getColGroup(grid, 'Location'); - expect(locationColGroup.width).toBe((Math.round(colWidth) * 3) + 'px'); + expect(locationColGroup.width).toBe((colWidth * 3) + 'px'); const countryColumn = grid.getColumnByName('Country'); expect(countryColumn.width).toBe(colWidthPx); const regionColumn = grid.getColumnByName('Region'); @@ -685,7 +685,7 @@ describe('IgxGrid - multi-column headers #grid', () => { fixture.detectChanges(); const locationColGroup = getColGroup(grid, 'Location'); - const expectedWidth = (Math.floor(grid.calcWidth * 0.2) * 3) + 'px'; + const expectedWidth = (grid.calcWidth * 0.2 * 3) + 'px'; expect(locationColGroup.width).toBe(expectedWidth); const countryColumn = grid.getColumnByName('Country'); expect(countryColumn.width).toBe(gridColWidth); @@ -717,7 +717,7 @@ describe('IgxGrid - multi-column headers #grid', () => { fixture.detectChanges(); const locationColGroup = getColGroup(grid, 'Location'); - const expectedWidth = (Math.floor(grid.calcWidth * 0.2) * 3) + 'px'; + const expectedWidth = (grid.calcWidth * 0.2 * 3) + 'px'; expect(locationColGroup.width).toBe(expectedWidth); const countryColumn = grid.getColumnByName('Country'); expect(countryColumn.width).toBe(columnWidth); @@ -739,11 +739,11 @@ describe('IgxGrid - multi-column headers #grid', () => { .querySelector("igx-grid-header") .getBoundingClientRect().width; const expectedWidth = headersWidth * 3; - expect(headersWidth).toBe(Math.floor((parseFloat(columnWidth) / 100) * grid.calcWidth)); + expect(parseFloat(headersWidth.toFixed(1))).toBe((parseFloat(columnWidth) / 100) * grid.calcWidth); const locationColGroupHeaderWidth = grid.nativeElement .querySelector("igx-grid-header-group") .getBoundingClientRect().width; - expect(locationColGroupHeaderWidth).toBe(expectedWidth); + expect(parseFloat(locationColGroupHeaderWidth.toFixed(1))).toBe(parseFloat(expectedWidth.toFixed(1))); }); }); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.multi-row-layout.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.multi-row-layout.spec.ts index 8813d4eef70..b252f3a6e3f 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.multi-row-layout.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.multi-row-layout.spec.ts @@ -43,10 +43,10 @@ describe('IgxGrid - multi-row-layout #grid', () => { const firstRowCellsArr = gridFirstRow.cells.toArray(); // the last cell is spaned as much as the first 3 cells - const firstThreeCellsWidth = firstRowCellsArr[0].nativeElement.offsetWidth + - firstRowCellsArr[1].nativeElement.offsetWidth + - firstRowCellsArr[2].nativeElement.offsetWidth; - const lastCellWidth = firstRowCellsArr[3].nativeElement.offsetWidth; + const firstThreeCellsWidth = firstRowCellsArr[0].nativeElement.getBoundingClientRect().width + + firstRowCellsArr[1].nativeElement.getBoundingClientRect().width + + firstRowCellsArr[2].nativeElement.getBoundingClientRect().width; + const lastCellWidth = firstRowCellsArr[3].nativeElement.getBoundingClientRect().width; expect(2 * firstRowCellsArr[0].nativeElement.offsetHeight).toEqual(firstRowCellsArr[3].nativeElement.offsetHeight); expect(firstThreeCellsWidth).toEqual(lastCellWidth); })); @@ -97,7 +97,10 @@ describe('IgxGrid - multi-row-layout #grid', () => { GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); // verify block style - expect(grid.columnList.first.getGridTemplate(false)).toBe('200px 200px 200px'); + let sizes = grid.columnList.first.getGridTemplate(false).split(' ').map(width => parseFloat(width).toFixed(2) + "px").join(' '); + + + expect(sizes).toBe('200.33px 200.33px 200.33px'); expect(grid.columnList.first.getGridTemplate(true)).toBe('repeat(3,1fr)'); // creating an incomplete layout 2 @@ -112,8 +115,8 @@ describe('IgxGrid - multi-row-layout #grid', () => { }]; fixture.componentInstance.grid.width = '617px'; fixture.detectChanges(); - - expect(grid.columnList.first.getGridTemplate(false)).toBe('200px 200px 200px'); + sizes = grid.columnList.first.getGridTemplate(false).split(' ').map(width => parseFloat(width).toFixed(2) + "px").join(' '); + expect(sizes).toBe('200.33px 200.33px 200.33px'); expect(grid.columnList.first.getGridTemplate(true)).toBe('repeat(3,1fr)'); })); @@ -129,11 +132,13 @@ describe('IgxGrid - multi-row-layout #grid', () => { expect(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'CompanyName').nativeElement.offsetWidth).toBe(200); expect(grid.gridAPI.get_cell_by_index(0, 'ContactName').nativeElement.offsetWidth).toBe(200); - expect(grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.offsetWidth).toBe(200 * 3); + expect(+grid.gridAPI.get_cell_by_index(0, 'ContactTitle').nativeElement.getBoundingClientRect().width.toFixed(3)) + .toBe(+(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.getBoundingClientRect().width * 3).toFixed(3)); // check group blocks let groupHeaderBlocks = fixture.debugElement.query(By.css('.igx-grid-thead')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); - expect(groupHeaderBlocks[0].nativeElement.clientWidth).toBe(200 * 3); + expect(+groupHeaderBlocks[0].nativeElement.getBoundingClientRect().width.toFixed(3)) + .toBe(+(grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement.getBoundingClientRect().width * 3).toFixed(3)); expect(groupHeaderBlocks[0].nativeElement.clientHeight).toBe(51 * 3); let gridFirstRow = grid.rowList.first; @@ -1051,7 +1056,7 @@ describe('IgxGrid - multi-row-layout #grid', () => { GridFunctions.verifyLayoutHeadersAreAligned(grid, gridFirstRow); const groupRowBlocks = fixture.debugElement.query(By.css('.igx-grid__tbody')).queryAll(By.css(GRID_MRL_BLOCK_CLASS)); - expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('118px 118px 118px 118px 118px 118px'); + expect(groupRowBlocks[0].nativeElement.style.gridTemplateColumns).toEqual('118.4px 118.4px 118.4px 118.4px 118.4px 118.4px'); })); it('should disregard hideGroupedColumns option and not hide columns when grouping when having column layouts.', fakeAsync(() => { diff --git a/projects/igniteui-angular/src/lib/grids/headers/pipes.ts b/projects/igniteui-angular/src/lib/grids/headers/pipes.ts index 0f6372fba51..7ba05b3e046 100644 --- a/projects/igniteui-angular/src/lib/grids/headers/pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/headers/pipes.ts @@ -22,7 +22,7 @@ export class IgxHeaderGroupWidthPipe implements PipeTransform { public transform(width: any, minWidth: any, hasLayout: boolean) { const isFitContent = width === 'fit-content'; - return hasLayout ? '' : isFitContent ? width : `${Math.max(parseInt(width), minWidth)}px`; + return hasLayout ? '' : isFitContent ? width : `${Math.max(parseFloat(width), minWidth)}px`; } } diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts index 93f2bb35078..4fadc7cee95 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts @@ -2054,7 +2054,7 @@ export class GridFunctions { } } const expectedWidth = Math.max(parseFloat(cell.column.calcWidth) * cell.column.gridColumnSpan, sum); - expect(cellElem.clientWidth - expectedWidth).toBeLessThan(1); + expect(cellElem.getBoundingClientRect().width - expectedWidth).toBeLessThan(1); // check height const expectedHeight = cell.grid.rowHeight * cell.gridRowSpan; expect(cellElem.offsetHeight).toBe(expectedHeight);