From 67ecaec6f2048f3ebef37a728f71286c28927b73 Mon Sep 17 00:00:00 2001 From: Ed Morales Date: Wed, 15 Aug 2018 16:43:25 -0700 Subject: [PATCH] feat(data-table): add ability to manually resize columns (#1008) * 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 --- .../data-table/data-table.component.html | 5 ++ .../data-table/data-table.component.ts | 1 + src/platform/core/data-table/README.md | 1 - .../core/data-table/_data-table-theme.scss | 14 ++++ .../data-table-column.component.html | 1 + .../core/data-table/data-table.component.html | 39 ++++++---- .../core/data-table/data-table.component.scss | 17 +++++ .../core/data-table/data-table.component.ts | 74 +++++++++++++++++++ 8 files changed, 138 insertions(+), 14 deletions(-) diff --git a/src/app/components/components/data-table/data-table.component.html b/src/app/components/components/data-table/data-table.component.html index 55e92ee614..a90d5b97f8 100644 --- a/src/app/components/components/data-table/data-table.component.html +++ b/src/app/components/components/data-table/data-table.component.html @@ -198,6 +198,7 @@

Paging Bar / Search Box / Sortable components

[multiple]="multiple" [sortable]="true" [sortBy]="sortBy" + [resizableColumns]="resizableColumns" [(ngModel)]="selectedRows" [sortOrder]="sortOrder" (sortChange)="sort($event)" @@ -243,6 +244,7 @@

No results to display.

[multiple]="multiple" [sortable]="true" [sortBy]="sortBy" + [resizableColumns]="resizableColumns" [(ngModel)]="selectedRows" [sortOrder]="sortOrder" (sortChange)="sort($event)" @@ -366,6 +368,9 @@

No results to display.

Tooltips on column headers + + Resizable columns +
diff --git a/src/app/components/components/data-table/data-table.component.ts b/src/app/components/components/data-table/data-table.component.ts index 8211ecea13..5fd68211fe 100644 --- a/src/app/components/components/data-table/data-table.component.ts +++ b/src/app/components/components/data-table/data-table.component.ts @@ -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[]; diff --git a/src/platform/core/data-table/README.md b/src/platform/core/data-table/README.md index 3390dd51a7..d54a4c1373 100644 --- a/src/platform/core/data-table/README.md +++ b/src/platform/core/data-table/README.md @@ -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: diff --git a/src/platform/core/data-table/_data-table-theme.scss b/src/platform/core/data-table/_data-table-theme.scss index 1726183214..53a48c3c44 100644 --- a/src/platform/core/data-table/_data-table-theme.scss +++ b/src/platform/core/data-table/_data-table-theme.scss @@ -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 { diff --git a/src/platform/core/data-table/data-table-column/data-table-column.component.html b/src/platform/core/data-table/data-table-column/data-table-column.component.html index e55e645953..6f01388e8b 100644 --- a/src/platform/core/data-table/data-table-column/data-table-column.component.html +++ b/src/platform/core/data-table/data-table-column/data-table-column.component.html @@ -17,3 +17,4 @@ arrow_upward + diff --git a/src/platform/core/data-table/data-table.component.html b/src/platform/core/data-table/data-table.component.html index b5b8918237..87c437df24 100644 --- a/src/platform/core/data-table/data-table.component.html +++ b/src/platform/core/data-table/data-table.component.html @@ -1,7 +1,8 @@ - + diff --git a/src/platform/core/data-table/data-table.component.scss b/src/platform/core/data-table/data-table.component.scss index bf5c741a3f..ffc20660ea 100644 --- a/src/platform/core/data-table/data-table.component.scss +++ b/src/platform/core/data-table/data-table.component.scss @@ -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 { diff --git a/src/platform/core/data-table/data-table.component.ts b/src/platform/core/data-table/data-table.component.ts index a4384ed1ad..5bcc8c8b0c 100644 --- a/src/platform/core/data-table/data-table.component.ts +++ b/src/platform/core/data-table/data-table.component.ts @@ -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 = new Subject(); + + 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 @@ -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. @@ -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) => { @@ -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(); } @@ -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 */
- {{column.label}} + #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)"> + {{column.label}} + + +