Skip to content

Add support for Column Resizing and AutoSizing of % widths #7662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 1, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,44 @@ export class IgxColumnComponent implements AfterContentInit {
@WatchColumnChanges()
@Input()
public maxWidth: string;

/**
* @hidden
*/
get maxWidthPx() {
const gridAvailableSize = this.grid.calcWidth;
const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
return isPercentageWidth ? parseFloat(this.maxWidth) / 100 * gridAvailableSize : parseFloat(this.maxWidth);
}

/**
* @hidden
*/
get maxWidthPercent() {
const gridAvailableSize = this.grid.calcWidth;
const isPercentageWidth = this.maxWidth && typeof this.maxWidth === 'string' && this.maxWidth.indexOf('%') !== -1;
return isPercentageWidth ? parseFloat(this.maxWidth) : parseFloat(this.maxWidth) / gridAvailableSize * 100;
}

/**
* @hidden
*/
get minWidthPx() {
const gridAvailableSize = this.grid.calcWidth;
const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
return isPercentageWidth ? parseFloat(this.minWidth) / 100 * gridAvailableSize : parseFloat(this.minWidth);
}

/**
* @hidden
*/
get minWidthPercent() {
const gridAvailableSize = this.grid.calcWidth;
const isPercentageWidth = this.minWidth && typeof this.minWidth === 'string' && this.minWidth.indexOf('%') !== -1;
return isPercentageWidth ? parseFloat(this.minWidth) : parseFloat(this.minWidth) / gridAvailableSize * 100;
}


/**
* Sets/gets the minimum `width` of the column.
* Default value is `88`;
Expand Down Expand Up @@ -1754,12 +1792,30 @@ export class IgxColumnComponent implements AfterContentInit {
*/
public autosize(byHeader = false) {
if (!this.columnGroup) {
this.width = !byHeader ? this.getLargestCellWidth() :
(Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
const size = this.getAutoSize(byHeader);
this.width = size;
this.grid.reflow();
}
}

/**
* @hidden
*/
public getAutoSize(byHeader = false) {
const size = !byHeader ? this.getLargestCellWidth() :
(Object.values(this.getHeaderCellWidths()).reduce((a, b) => a + b) + 'px');
const gridAvailableSize = this.grid.calcWidth;
let newWidth;
const isPercentageWidth = this.width && typeof this.width === 'string' && this.width.indexOf('%') !== -1;
if (isPercentageWidth) {
const percentageSize = parseFloat(size) / gridAvailableSize * 100;
newWidth = percentageSize + '%';
} else {
newWidth = size;
}
return newWidth;
}

/**
* @hidden
*/
Expand Down Expand Up @@ -1880,14 +1936,14 @@ export class IgxColumnComponent implements AfterContentInit {
const colWidth = this.width;
const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
if (isPercentageWidth) {
this._calcWidth = parseInt(colWidth, 10) / 100 * grid.calcWidth;
this._calcWidth = parseFloat(colWidth) / 100 * grid.calcWidth;
} else if (!colWidth) {
// no width
this._calcWidth = this.defaultWidth || grid.getPossibleColumnWidth();
} else {
this._calcWidth = this.width;
}
this.calcPixelWidth = parseInt(this._calcWidth, 10);
this.calcPixelWidth = parseFloat(this._calcWidth);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3552,7 +3552,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
if (this.hasColumnLayouts) {
return '';
}
const colWidth = parseInt(column.calcWidth, 10);
const colWidth = parseFloat(column.calcWidth);
const minWidth = this.defaultHeaderGroupMinWidth;

if (colWidth < minWidth) {
Expand Down
151 changes: 147 additions & 4 deletions projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,149 @@ describe('IgxGrid - Deferred Column Resizing #grid', () => {
}));
});

describe('Percentage tests: ', () => {
let fixture: ComponentFixture<any>;
let grid: IgxGridComponent;

beforeEach(fakeAsync(() => {
fixture = TestBed.createComponent(ColPercentageGridComponent);
fixture.detectChanges();
grid = fixture.componentInstance.grid;
}));

it('should resize columns with % width.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
const headers = GridFunctions.getColumnHeaders(fixture);
expect(grid.columns[0].width).toBe('25%');

const headerResArea = headers[0].parent.children[2].nativeElement;
const startPos = headerResArea.getBoundingClientRect().x;
UIInteractions.simulateMouseEvent('mousedown', headerResArea, startPos, 5);
tick(200);
fixture.detectChanges();

const resizer = GridFunctions.getResizer(fixture).nativeElement;
expect(resizer).toBeDefined();
// resize with 100px, which is 25%
UIInteractions.simulateMouseEvent('mousemove', resizer, startPos + 100, 5);
UIInteractions.simulateMouseEvent('mouseup', resizer, startPos + 100, 5);
fixture.detectChanges();
expect(grid.columns[0].width).toBe('50%');
}));

it('should resize columns with % width and % maxWidth.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
const headers = GridFunctions.getColumnHeaders(fixture);
grid.columns[0].maxWidth = '30%';
expect(grid.columns[0].width).toBe('25%');

const headerResArea = headers[0].parent.children[2].nativeElement;
const startPos = headerResArea.getBoundingClientRect().x;
UIInteractions.simulateMouseEvent('mousedown', headerResArea, startPos, 5);
tick(200);
fixture.detectChanges();

const resizer = GridFunctions.getResizer(fixture).nativeElement;
expect(resizer).toBeDefined();
// resize with +100px, which is 25%
UIInteractions.simulateMouseEvent('mousemove', resizer, startPos + 100, 5);
UIInteractions.simulateMouseEvent('mouseup', resizer, startPos + 100, 5);
fixture.detectChanges();

expect(grid.columns[0].width).toBe(grid.columns[0].maxWidth);
}));

it('should resize columns with % width and % minWidth.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
const headers = GridFunctions.getColumnHeaders(fixture);
grid.columns[0].minWidth = '10%';
expect(grid.columns[0].width).toBe('25%');

const headerResArea = headers[0].parent.children[2].nativeElement;
const startPos = headerResArea.getBoundingClientRect().x;
UIInteractions.simulateMouseEvent('mousedown', headerResArea, startPos, 5);
tick(200);
fixture.detectChanges();

const resizer = GridFunctions.getResizer(fixture).nativeElement;
// resize with -100px
UIInteractions.simulateMouseEvent('mousemove', resizer, startPos - 100, 5);
UIInteractions.simulateMouseEvent('mouseup', resizer, startPos - 100, 5);
fixture.detectChanges();

expect(grid.columns[0].width).toBe(grid.columns[0].minWidth);
}));

it('should resize columns with % width and pixel maxWidth.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
const headers = GridFunctions.getColumnHeaders(fixture);
grid.columns[0].maxWidth = '200px';
expect(grid.columns[0].width).toBe('25%');

const headerResArea = headers[0].parent.children[2].nativeElement;
const startPos = headerResArea.getBoundingClientRect().x;
UIInteractions.simulateMouseEvent('mousedown', headerResArea, startPos, 5);
tick(200);
fixture.detectChanges();

const resizer = GridFunctions.getResizer(fixture).nativeElement;
expect(resizer).toBeDefined();
// resize with +200px, which is 50%
UIInteractions.simulateMouseEvent('mousemove', resizer, startPos + 200, 5);
UIInteractions.simulateMouseEvent('mouseup', resizer, startPos + 200, 5);
fixture.detectChanges();
expect(grid.columns[0].width).toBe('50%');
}));

it('should resize columns with % width and pixel minWidth.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
const headers = GridFunctions.getColumnHeaders(fixture);
// minWidth is 12.5% of the grid width - 400px
grid.columns[0].minWidth = '50px';
expect(grid.columns[0].width).toBe('25%');

const headerResArea = headers[0].parent.children[2].nativeElement;
const startPos = headerResArea.getBoundingClientRect().x;
UIInteractions.simulateMouseEvent('mousedown', headerResArea, startPos, 5);
tick(200);
fixture.detectChanges();

const resizer = GridFunctions.getResizer(fixture).nativeElement;
// resize with -100px
UIInteractions.simulateMouseEvent('mousemove', resizer, startPos - 100, 5);
UIInteractions.simulateMouseEvent('mouseup', resizer, startPos - 100, 5);
fixture.detectChanges();

expect(grid.columns[0].width).toBe('12.5%');
}));

it('should autosize column with % width programmatically.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
expect(grid.columns[0].width).toBe('25%');
grid.columns[0].autosize();
fixture.detectChanges();
expect(grid.columns[0].width).toBe('21%');
}));

it('should autosize column with % width on double click.', fakeAsync(() => {
grid.height = null;
fixture.detectChanges();
expect(grid.columns[0].width).toBe('25%');
const headers = GridFunctions.getColumnHeaders(fixture);
const headerResArea = headers[0].parent.children[2].nativeElement;
UIInteractions.simulateMouseEvent('dblclick', headerResArea, 0, 0);
tick(200);
fixture.detectChanges();
expect(grid.columns[0].width).toBe('21%');
}));
});

describe('Integration tests: ', () => {
let fixture: ComponentFixture<any>;
let grid: IgxGridComponent;
Expand Down Expand Up @@ -453,8 +596,8 @@ describe('IgxGrid - Deferred Column Resizing #grid', () => {
UIInteractions.simulateMouseEvent('mouseup', resizer, 550, 5);
fixture.detectChanges();

expect(grid.columns[2].width).toEqual('250px');
expect(grid.columns[2].cells[0].value).toEqual(254);
// column has maxWidth='150px'
expect(grid.columns[1].width).toEqual('150px');

GridFunctions.clickHeaderSortIcon(headers[2]);
GridFunctions.clickHeaderSortIcon(headers[2]);
Expand Down Expand Up @@ -508,7 +651,7 @@ describe('IgxGrid - Deferred Column Resizing #grid', () => {
UIInteractions.simulateMouseEvent('mouseup', resizer, 300, 5);
fixture.detectChanges();

let resizingArgs: IColumnResizeEventArgs = { column: grid.columns[0], prevWidth: '150', newWidth: '300px' };
let resizingArgs: IColumnResizeEventArgs = { column: grid.columns[0], prevWidth: '150px', newWidth: '300px' };
expect(grid.columns[0].width).toEqual('300px');
expect(resizingSpy).toHaveBeenCalledTimes(1);
expect(resizingSpy).toHaveBeenCalledWith(resizingArgs);
Expand Down Expand Up @@ -805,7 +948,7 @@ export class ColGridComponent implements OnInit {

@Component({
template: GridTemplateStrings.declareGrid(`width="400px" height="600px" [allowFiltering]="true"`, ``,
`<igx-column [field]="'Items'" [width]="'25%'" dataType="string" [filterable]="true"></igx-column>
`<igx-column [field]="'Items'" [width]="'25%'" dataType="string" [filterable]="true" [resizable]="true"></igx-column>
<igx-column [field]="'ID'" [width]="'25%'" [header]="'ID'" [filterable]="true"></igx-column>
<igx-column [field]="'ProductName'" [width]="'25%'" dataType="string" [filterable]="true"></igx-column>
<igx-column [field]="'Test'"[width]="'25%'" dataType="string" [resizable]="true"></igx-column>`
Expand Down
Loading