Skip to content

Commit 0a7024f

Browse files
committed
feat: resize column to fit content on double click
1 parent 4aae763 commit 0a7024f

File tree

5 files changed

+79
-1
lines changed

5 files changed

+79
-1
lines changed

projects/ngx-datatable/src/lib/components/body/body-row.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { DataTableBodyCellComponent } from './body-cell.component';
4343
<datatable-body-cell
4444
role="cell"
4545
tabindex="-1"
46+
[attr.header-id]="column.$$id"
4647
[row]="row"
4748
[group]="group"
4849
[expanded]="expanded"

projects/ngx-datatable/src/lib/components/datatable.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
(sort)="onColumnSort($event)"
2525
(resize)="onColumnResize($event)"
2626
(resizing)="onColumnResizing($event)"
27+
(fitToContent)="onColumnFitToContent($event)"
2728
(reorder)="onColumnReorder($event)"
2829
(select)="onHeaderSelect()"
2930
(columnContextmenu)="onColumnContextmenu($event)"

projects/ngx-datatable/src/lib/components/datatable.component.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ export class DatatableComponent<TRow extends Row = any>
908908
}
909909

910910
/**
911-
* Recalulcates the column widths based on column width
911+
* Recalculates the column widths based on column width
912912
* distribution mode and scrollbar offsets.
913913
*/
914914
recalculateColumns(
@@ -1131,6 +1131,63 @@ export class DatatableComponent<TRow extends Row = any>
11311131
this.recalculateColumns(this._internalColumns, idx);
11321132
}
11331133

1134+
/**
1135+
* Triggered when double clicked on resize handler
1136+
*/
1137+
onColumnFitToContent({
1138+
headerElement,
1139+
column
1140+
}: {
1141+
headerElement: HTMLElement;
1142+
column: TableColumnInternal;
1143+
}): void {
1144+
const columnCells = Array.from(
1145+
this.bodyElement.nativeElement.querySelectorAll('datatable-body-cell')
1146+
);
1147+
1148+
const selectedColumnItems = columnCells.filter(
1149+
c => c.getAttribute('header-id') === column.$$id
1150+
);
1151+
1152+
// this element has to be a form, otherwise form elements within a cell
1153+
// will be validated while being cloned. This can cause issues such as
1154+
// radio buttons being reset and losing their values.
1155+
const eDummyContainer = document.createElement('form');
1156+
// position fixed, so it isn't restricted to the boundaries of the parent
1157+
eDummyContainer.style.position = 'fixed';
1158+
eDummyContainer.style.padding = '16px';
1159+
1160+
const eBodyContainer = this.bodyElement.nativeElement;
1161+
1162+
selectedColumnItems
1163+
.concat(headerElement)
1164+
.forEach(el => this.cloneItemIntoDummy(el, eDummyContainer));
1165+
1166+
eBodyContainer.appendChild(eDummyContainer);
1167+
1168+
const dummyContainerWidth = eDummyContainer.offsetWidth;
1169+
1170+
// we are finished with the dummy container, so get rid of it
1171+
eBodyContainer.removeChild(eDummyContainer);
1172+
1173+
this.onColumnResize({ column, newValue: dummyContainerWidth, prevValue: column.width });
1174+
}
1175+
1176+
private cloneItemIntoDummy(eCell: Element, eDummyContainer: HTMLElement): void {
1177+
// make a deep clone of the cell
1178+
const eCellClone: HTMLElement = eCell.cloneNode(true) as HTMLElement;
1179+
// the original has a fixed width, we remove this to allow the natural width based on content
1180+
eCellClone.style.width = '';
1181+
// the original has position = absolute, we need to remove this so it's positioned normally
1182+
eCellClone.style.position = 'static';
1183+
eCellClone.style.left = '';
1184+
1185+
const eCloneParent = document.createElement('div');
1186+
1187+
eCloneParent.append(eCellClone);
1188+
eDummyContainer.appendChild(eCloneParent);
1189+
}
1190+
11341191
/**
11351192
* The header triggered a column re-order event.
11361193
*/

projects/ngx-datatable/src/lib/components/header/header-cell.component.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export class DataTableHeaderCellComponent implements OnInit, OnDestroy {
140140
}>(false);
141141
@Output() readonly resize = new EventEmitter<{ width: number; column: TableColumnInternal }>();
142142
@Output() readonly resizing = new EventEmitter<{ width: number; column: TableColumnInternal }>();
143+
@Output() readonly fitToContent = new EventEmitter<HTMLElement>();
143144

144145
@HostBinding('class')
145146
get columnCssClasses(): string {
@@ -242,6 +243,15 @@ export class DataTableHeaderCellComponent implements OnInit, OnDestroy {
242243
this.onSort();
243244
}
244245

246+
@HostListener('dblclick', ['$event'])
247+
onDblClick(event: MouseEvent): void {
248+
const isHandle = (event.target as HTMLElement).classList.contains('resize-handle');
249+
if (isHandle) {
250+
event.stopPropagation();
251+
this.fitToContent.emit(this.element);
252+
}
253+
}
254+
245255
ngOnInit() {
246256
this.sortClass = this.calcSortClass(this.sortDir);
247257
// If there is already a default sort then start the counter with 1.

projects/ngx-datatable/src/lib/components/header/header.component.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import { DataTableHeaderCellComponent } from './header-cell.component';
8585
[ariaHeaderCheckboxMessage]="ariaHeaderCheckboxMessage"
8686
(resize)="onColumnResized($event)"
8787
(resizing)="onColumnResizing($event)"
88+
(fitToContent)="onColumnFitToContent($event, column)"
8889
(longPressStart)="onLongPressStart($event)"
8990
(longPressEnd)="onLongPressEnd($event)"
9091
(sort)="onSort($event)"
@@ -199,6 +200,10 @@ export class DataTableHeaderComponent implements OnDestroy, OnChanges {
199200
event: MouseEvent;
200201
column: TableColumnInternal;
201202
}>(false);
203+
@Output() readonly fitToContent = new EventEmitter<{
204+
headerElement: HTMLElement;
205+
column: TableColumnInternal;
206+
}>();
202207

203208
_columnsByPin!: PinnedColumns[];
204209
_columnGroupWidths: any = {
@@ -275,6 +280,10 @@ export class DataTableHeaderComponent implements OnDestroy, OnChanges {
275280
this.resizing.emit(this.makeResizeEvent(width, column));
276281
}
277282

283+
onColumnFitToContent(headerElement: HTMLElement, column: TableColumnInternal) {
284+
this.fitToContent.emit({ headerElement, column });
285+
}
286+
278287
private makeResizeEvent(
279288
width: number,
280289
column: TableColumnInternal<Row>

0 commit comments

Comments
 (0)