Skip to content

Commit

Permalink
feat(data-table): add ability to manually resize columns (#1008)
Browse files Browse the repository at this point in the history
* feat(data-table): add ability to manually resize columns (overrides width configuration)

* fix(): remove unneeded rules

* fix(): make separator be centered when dragging

also fix bug when clicking on separator and not dragging it

* fix(): add comments in code and made separator line opaque instead of hidden

* fix(): resizing issue in firefox

* fix(): check if resizeColumn is not undefined explicitly
  • Loading branch information
emoralesb05 authored and jeremysmartt committed Aug 15, 2018
1 parent 992c296 commit 67ecaec
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ <h4 class="mat-subheading-2">Paging Bar / Search Box / Sortable components</h4>
[multiple]="multiple"
[sortable]="true"
[sortBy]="sortBy"
[resizableColumns]="resizableColumns"
[(ngModel)]="selectedRows"
[sortOrder]="sortOrder"
(sortChange)="sort($event)"
Expand Down Expand Up @@ -243,6 +244,7 @@ <h3>No results to display.</h3>
[multiple]="multiple"
[sortable]="true"
[sortBy]="sortBy"
[resizableColumns]="resizableColumns"
[(ngModel)]="selectedRows"
[sortOrder]="sortOrder"
(sortChange)="sort($event)"
Expand Down Expand Up @@ -366,6 +368,9 @@ <h3>No results to display.</h3>
<mat-slide-toggle color="accent" (change)="toggleTooltips()">
Tooltips on column headers
</mat-slide-toggle>
<mat-slide-toggle color="accent" [(ngModel)]="resizableColumns">
Resizable columns
</mat-slide-toggle>
</div>
<mat-divider></mat-divider>
<div class="pad-sm">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class DataTableDemoComponent implements OnInit {
selectable: boolean = true;
clickable: boolean = false;
multiple: boolean = true;
resizableColumns: boolean = false;
filterColumn: boolean = true;

filteredData: any[];
Expand Down
1 change: 0 additions & 1 deletion src/platform/core/data-table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ Use [tdDataTableTemplate] directive for template support which gives context acc
+ refresh: function
+ Refreshes data table and rerenders [data] and [columns]


## Setup

Import the [CovalentDataTableModule] in your NgModule:
Expand Down
14 changes: 14 additions & 0 deletions src/platform/core/data-table/_data-table-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,23 @@
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);

td-data-table {
border-bottom: 1px solid mat-color($foreground, divider);
}
.td-data-table-scrollable {
border-top: 1px solid mat-color($foreground, divider);
}
.td-data-table-column-resizer {
.td-data-table-column-separator {
border-right: 2px solid mat-color($foreground, divider);
opacity: 0.3;
}
&:hover, &.td-resizing {
.td-data-table-column-separator {
opacity: 1;
}
}
}
table[td-data-table] {
.td-data-table-column-row,
.td-data-table-row {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
arrow_upward
</mat-icon>
</span>
<ng-content select="[td-column-resizer]"></ng-content>
39 changes: 26 additions & 13 deletions src/platform/core/data-table/data-table.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<table td-data-table
[style.left.px]="columnsLeftScroll"
[class.mat-selectable]="selectable">
<thead class="td-data-table-head">
<thead class="td-data-table-head"
(dragover)="_handleColumnDrag($event)">
<tr td-data-table-column-row>
<th td-data-table-column class="mat-checkbox-column" *ngIf="selectable">
<mat-checkbox
Expand All @@ -17,18 +18,30 @@
</mat-checkbox>
</th>
<th td-data-table-column
#columnElement
*ngFor="let column of columns; let i = index;"
[style.min-width.px]="getColumnWidth(i)"
[style.max-width.px]="getColumnWidth(i)"
[name]="column.name"
[numeric]="column.numeric"
[active]="(column.sortable || sortable) && column === sortByColumn"
[sortable]="column.sortable || (sortable && column.sortable !== false)"
[sortOrder]="sortOrderEnum"
[hidden]="column.hidden"
(sortChange)="handleSort(column)">
<span [matTooltip]="column.tooltip">{{column.label}}</span>
#columnElement
*ngFor="let column of columns; let i = index; let last = last"
[style.min-width.px]="getColumnWidth(i)"
[style.max-width.px]="getColumnWidth(i)"
[name]="column.name"
[numeric]="column.numeric"
[active]="(column.sortable || sortable) && column === sortByColumn"
[sortable]="column.sortable || (sortable && column.sortable !== false)"
[sortOrder]="sortOrderEnum"
[hidden]="column.hidden"
(sortChange)="handleSort(column)">
<span [matTooltip]="column.tooltip">{{column.label}}</span>
<span td-column-resizer
*ngIf="resizableColumns"
draggable="true"
class="td-data-table-column-resizer"
[class.td-resizing]="i === resizingColumn"
(mousedown)="_handleStartColumnDrag(i, $event)"
(dragstart)="$event?.dataTransfer?.setData('text', '')"
(drag)="_handleColumnDrag($event)"
(dragend)="_handleEndColumnDrag()"
(mouseup)="_handleEndColumnDrag()">
<span class="td-data-table-column-separator"></span>
</span>
</th>
</tr>
</thead>
Expand Down
17 changes: 17 additions & 0 deletions src/platform/core/data-table/data-table.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ $checkbox-size: 18px;
}
}

.td-data-table-column-resizer {
&, .td-data-table-column-separator {
position: absolute;
height: 100%;
top: 0;
}
.td-data-table-column-separator {
left: 2px;
}
right: 0;
width: 6px;
cursor: col-resize;
&.td-resizing {
cursor: -webkit-grabbing;
}
}

table.td-data-table {
width: auto !important;
&.mat-selectable tbody > tr.td-data-table-row {
Expand Down
74 changes: 74 additions & 0 deletions src/platform/core/data-table/data-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ export class TdDataTableComponent extends _TdDataTableMixinBase implements ICont
private _rowsChangedSubs: Subscription;
private _hostWidth: number = 0;

/** manually resizable columns */
private _resizableColumns: boolean = false;
private _columnClientX: number = 0;
private _columnResizeSubs: Subscription;
private _resizingColumn: number;
private _onColumnResize: Subject<number> = new Subject<number>();

get resizingColumn(): number {
return this._resizingColumn;
}

get hostWidth(): number {
// if the checkboxes are rendered, we need to remove their width
// from the total width to calculate properly
Expand Down Expand Up @@ -271,6 +282,19 @@ export class TdDataTableComponent extends _TdDataTableMixinBase implements ICont
}
}

/**
* resizableColumns?: boolean
* Enables manual column resize.
* Defaults to 'false'
*/
@Input('resizableColumns')
set resizableColumns(resizableColumns: boolean) {
this._resizableColumns = coerceBooleanProperty(resizableColumns);
}
get resizableColumns(): boolean {
return this._resizableColumns;
}

/**
* selectable?: boolean
* Enables row selection events, hover and selected row states.
Expand Down Expand Up @@ -426,6 +450,15 @@ export class TdDataTableComponent extends _TdDataTableMixinBase implements ICont
this._calculateWidths();
this._calculateVirtualRows();
});

// initialize observable for column resize calculations
this._columnResizeSubs = this._onColumnResize.asObservable().pipe(
debounceTime(0),
).subscribe((clientX: number) => {
this._columnClientX = clientX;
this._calculateWidths();
this._changeDetectorRef.markForCheck();
});
// initialize observable for scroll column header reposition
this._horizontalScrollSubs = this._onHorizontalScroll.asObservable()
.subscribe((horizontalScroll: number) => {
Expand Down Expand Up @@ -499,6 +532,9 @@ export class TdDataTableComponent extends _TdDataTableMixinBase implements ICont
if (this._resizeSubs) {
this._resizeSubs.unsubscribe();
}
if (this._columnResizeSubs) {
this._columnResizeSubs.unsubscribe();
}
if (this._horizontalScrollSubs) {
this._horizontalScrollSubs.unsubscribe();
}
Expand Down Expand Up @@ -779,6 +815,44 @@ export class TdDataTableComponent extends _TdDataTableMixinBase implements ICont
}
}

/**
* Sets column index of the dragged column and initial clientX of column
*/
_handleStartColumnDrag(index: number, event: MouseEvent): void {
this._columnClientX = event.clientX;
this._resizingColumn = index;
}

/**
* Calculates new width depending on new clientX of dragger column
*/
_handleColumnDrag(event: MouseEvent | DragEvent): void {
// check if there was been a separator clicked for resize
if (this._resizingColumn !== undefined && event.clientX > 0) {
let xPosition: number = event.clientX;
// checks if the separator is being moved to try and resize the column, else dont do anything
if (xPosition > 0 && this._columnClientX > 0 && (xPosition - this._columnClientX) !== 0) {
// calculate the new width depending if making the column bigger or smaller
let proposedManualWidth: number = this._widths[this._resizingColumn].value + (xPosition - this._columnClientX);
// if the proposed new width is less than the projected min width of the column, use projected min width
if (proposedManualWidth < this._colElements.toArray()[this._resizingColumn].projectedWidth) {
proposedManualWidth = this._colElements.toArray()[this._resizingColumn].projectedWidth;
}
this.columns[this._resizingColumn].width = proposedManualWidth;
// update new x position for the resized column
this._onColumnResize.next(xPosition);
}
}
}

/**
* Ends dragged flags
*/
_handleEndColumnDrag(): void {
this._columnClientX = undefined;
this._resizingColumn = undefined;
}

/**
* Method to prevent the default events
*/
Expand Down

0 comments on commit 67ecaec

Please sign in to comment.