Skip to content

Commit ba3f3bc

Browse files
committed
Handle flex and tables both
1 parent d197464 commit ba3f3bc

16 files changed

+393
-100
lines changed
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import {NgModule} from '@angular/core';
22

3-
import {CdkColumnResize, CdkDefaultEnabledColumnResize} from './column-resize';
3+
import {
4+
CdkColumnResize,
5+
CdkColumnResizeFlex,
6+
CdkDefaultEnabledColumnResize,
7+
CdkDefaultEnabledColumnResizeFlex,
8+
} from './column-resize';
49

510
@NgModule({
6-
declarations: [CdkDefaultEnabledColumnResize],
7-
exports: [CdkDefaultEnabledColumnResize],
11+
declarations: [CdkDefaultEnabledColumnResize, CdkDefaultEnabledColumnResizeFlex],
12+
exports: [CdkDefaultEnabledColumnResize, CdkDefaultEnabledColumnResizeFlex],
813
})
914
export class CdkColumnResizeDefaultEnabledModule {}
1015

1116
@NgModule({
12-
declarations: [CdkColumnResize],
13-
exports: [CdkColumnResize],
17+
declarations: [CdkColumnResize, CdkColumnResizeFlex],
18+
exports: [CdkColumnResize, CdkColumnResizeFlex],
1419
})
1520
export class CdkColumnResizeModule {}

src/cdk-experimental/column-resize/column-resize.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ import {matches} from '../popover-edit/polyfill';
88
import {ColumnResizeNotifier, _ColumnResizeNotifierSource} from './column-resize-notifier';
99
import {HEADER_CELL_SELECTOR, RESIZE_OVERLAY_SELECTOR} from './constants';
1010
import {_HeaderRowEventDispatcher} from './event-dispatcher';
11+
import {
12+
TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER,
13+
FLEX_RESIZE_STRATEGY_PROVIDER,
14+
} from './resize-strategy';
1115

1216
import {closest} from '../popover-edit/polyfill';
1317

1418
const PROVIDERS = [ColumnResizeNotifier, _HeaderRowEventDispatcher, _ColumnResizeNotifierSource];
19+
const TABLE_PROVIDERS = [...PROVIDERS, TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER];
20+
const FLEX_PROVIDERS = [...PROVIDERS, FLEX_RESIZE_STRATEGY_PROVIDER];
1521
const HOST_BINDINGS = {
1622
'[class]': 'getIdClass()',
1723
'[class.column-resize-rtl]': 'directionality.value === "rtl"',
@@ -109,9 +115,12 @@ export abstract class ColumnResize implements AfterViewInit, OnDestroy {
109115
}
110116

111117
@Directive({
112-
selector: 'cdk-table, table[cdk-table]',
118+
selector: 'table[cdk-table]',
113119
host: HOST_BINDINGS,
114-
providers: [...PROVIDERS, {provide: ColumnResize, useExisting: CdkDefaultEnabledColumnResize}],
120+
providers: [
121+
...TABLE_PROVIDERS,
122+
{provide: ColumnResize, useExisting: CdkDefaultEnabledColumnResize},
123+
],
115124
})
116125
export class CdkDefaultEnabledColumnResize extends ColumnResize {
117126
constructor(
@@ -125,9 +134,31 @@ export class CdkDefaultEnabledColumnResize extends ColumnResize {
125134
}
126135

127136
@Directive({
128-
selector: 'cdk-table[columnResize], table[cdk-table][columnResize]',
137+
selector: 'cdk-table',
129138
host: HOST_BINDINGS,
130-
providers: [...PROVIDERS, {provide: ColumnResize, useExisting: CdkColumnResize}],
139+
providers: [
140+
...FLEX_PROVIDERS,
141+
{provide: ColumnResize, useExisting: CdkDefaultEnabledColumnResizeFlex},
142+
],
143+
})
144+
export class CdkDefaultEnabledColumnResizeFlex extends ColumnResize {
145+
constructor(
146+
readonly directionality: Directionality,
147+
protected readonly elementRef: ElementRef,
148+
protected readonly eventDispatcher: _HeaderRowEventDispatcher,
149+
protected readonly ngZone: NgZone,
150+
protected readonly notifier: _ColumnResizeNotifierSource) {
151+
super();
152+
}
153+
}
154+
155+
@Directive({
156+
selector: 'table[cdk-table][columnResize]',
157+
host: HOST_BINDINGS,
158+
providers: [
159+
...TABLE_PROVIDERS,
160+
{provide: ColumnResize, useExisting: CdkColumnResize},
161+
],
131162
})
132163
export class CdkColumnResize extends ColumnResize {
133164
constructor(
@@ -139,3 +170,22 @@ export class CdkColumnResize extends ColumnResize {
139170
super();
140171
}
141172
}
173+
174+
@Directive({
175+
selector: 'cdk-table[columnResize]',
176+
host: HOST_BINDINGS,
177+
providers: [
178+
...FLEX_PROVIDERS,
179+
{provide: ColumnResize, useExisting: CdkColumnResizeFlex},
180+
],
181+
})
182+
export class CdkColumnResizeFlex extends ColumnResize {
183+
constructor(
184+
readonly directionality: Directionality,
185+
protected readonly elementRef: ElementRef,
186+
protected readonly eventDispatcher: _HeaderRowEventDispatcher,
187+
protected readonly ngZone: NgZone,
188+
protected readonly notifier: _ColumnResizeNotifierSource) {
189+
super();
190+
}
191+
}

src/cdk-experimental/column-resize/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export * from './column-size-store';
1313
export * from './event-dispatcher';
1414
export * from './resizable';
1515
export * from './resize-ref';
16+
export * from './resize-strategy';
1617
export * from './overlay-handle';

src/cdk-experimental/column-resize/resizable.ts

Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {DOCUMENT} from '@angular/common';
1212
import {ComponentPortal, PortalInjector} from '@angular/cdk/portal';
1313
import {Overlay, OverlayRef} from '@angular/cdk/overlay';
1414
import {CdkColumnDef} from '@angular/cdk/table';
15-
import {coerceCssPixelValue} from '@angular/cdk/coercion';
1615
import {merge, ReplaySubject} from 'rxjs';
1716
import {filter, takeUntil} from 'rxjs/operators';
1817

@@ -24,6 +23,7 @@ import {ColumnResize} from './column-resize';
2423
import {ColumnSizeAction, _ColumnResizeNotifierSource} from './column-resize-notifier';
2524
import {_HeaderRowEventDispatcher} from './event-dispatcher';
2625
import {ResizeRef} from './resize-ref';
26+
import {ResizeStrategy} from './resize-strategy';
2727

2828
export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
2929
implements AfterViewInit, OnDestroy {
@@ -34,8 +34,6 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
3434
protected overlayRef?: OverlayRef;
3535
protected readonly destroyed = new ReplaySubject<void>();
3636
protected readonly document: Document;
37-
38-
private _styleElement?: HTMLStyleElement;
3937

4038
constructor(
4139
protected readonly columnDef: CdkColumnDef,
@@ -47,6 +45,7 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
4745
protected readonly ngZone: NgZone,
4846
protected readonly overlay: Overlay,
4947
protected readonly resizeNotifier: _ColumnResizeNotifierSource,
48+
protected readonly resizeStrategy: ResizeStrategy,
5049
protected readonly viewContainerRef: ViewContainerRef) {
5150
this.document = document;
5251
}
@@ -68,20 +67,14 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
6867
if (this.overlayRef) {
6968
this.overlayRef.dispose();
7069
}
71-
72-
// TODO: Use remove() once we're off IE11.
73-
if (this._styleElement && this._styleElement.parentNode) {
74-
this._styleElement.parentNode.removeChild(this._styleElement);
75-
}
7670
}
7771

7872
protected abstract getInlineHandleCssClassName(): string;
7973

8074
protected abstract createOverlayForHandle(): OverlayRef;
8175

8276
protected abstract getOverlayHandleComponentType(): Type<HandleComponent>;
83-
84-
protected abstract getColumnCssClassName(): string;
77+
8578

8679
private _listenForRowHoverEvents(): void {
8780
const element = this.elementRef.nativeElement!;
@@ -161,71 +154,13 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
161154

162155
private _applySize(sizeInPixels: number): void {
163156
const sizeToApply = Math.min(Math.max(sizeInPixels, this.minPx, 0), this.maxPx);
164-
/* const columnClassName = this.getColumnCssClassName();
165-
const tableClassName = this.columnResize.getIdClass();
166-
167-
const selector = `.${tableClassName} .${columnClassName}`;*/
168-
const width = coerceCssPixelValue(sizeToApply);
169-
170-
// approach 0 (issues if number or order of cols change)
171-
// also does not work, seemingly
172-
/* const table = document.querySelector(`.${tableClassName}`);
173-
const cols = table!.querySelectorAll('col');
174-
const index = Array.from(this.elementRef.nativeElement!.parentNode.childNodes).indexOf(this.elementRef.nativeElement!);
175-
176-
cols[index].style.width = width;*/
177-
178-
// approach 1 (no subsequent updates though)
179-
/* const cells = Array.from(document.querySelectorAll(selector)) as HTMLElement[];
180-
for (const cell of cells) {
181-
cell.style.width = width;
182-
}*/
183-
184-
// approach 1a
185-
/* cells[0].style.width = width;*/
186157

187-
// approach 1b
188-
189-
// With table-layout: fixed, all we have to do is set the size on the
190-
// header element and the whole column will update.
191-
// This is by far the fastest way to resize a table column tested.
192-
// Also tested: resizing by adding CSS selectors, selectors with CSS variables.
193-
this.elementRef.nativeElement!.style.boxSizing = 'border-box';
194-
this.elementRef.nativeElement!.style.width = width;
195-
196-
//////////
197-
// todo: for flex-based tables, we'll need a different approach.
198-
//////////
199-
200-
// approach 2
201-
/* if (!this._styleElement) {
202-
this._styleElement = this.document.createElement('style');
203-
this._styleElement.appendChild(this.document.createTextNode(''));
204-
this.document.head.appendChild(this._styleElement);
205-
} else {
206-
(this._styleElement.sheet as CSSStyleSheet).deleteRule(0);
207-
}
208-
(this._styleElement.sheet as CSSStyleSheet).insertRule(
209-
`${selector} {box-sizing: border-box;width:${width}}`, 0);*/
210-
211-
// approach 2.5
212-
213-
/* const cssVar = `--resizable-${tableClassName}--${columnClassName}--width`;
214-
document.documentElement.style.setProperty(cssVar, width);
215-
if (!this._styleElement) {
216-
this._styleElement = this.document.createElement('style');
217-
this._styleElement.appendChild(this.document.createTextNode(''));
218-
this.document.head.appendChild(this._styleElement);
219-
220-
221-
const sheet = this._styleElement.sheet as CSSStyleSheet;
222-
223-
sheet.insertRule(`${selector} {width:var(${cssVar})}`, 0);
224-
}*/
158+
this.resizeStrategy.applyColumnSize(this.columnDef.cssClassFriendlyName,
159+
this.elementRef.nativeElement!, sizeToApply);
225160
}
226161

227162
private _appendInlineHandle(): void {
228-
this.inlineHandle = document.createElement('div');
163+
this.inlineHandle = this.document.createElement('div');
229164
this.inlineHandle.tabIndex = 0;
230165
this.inlineHandle.className = this.getInlineHandleCssClassName();
231166

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import {Inject, Injectable, OnDestroy, Provider} from '@angular/core';
2+
import {DOCUMENT} from '@angular/common';
3+
import {coerceCssPixelValue} from '@angular/cdk/coercion';
4+
5+
import {ColumnResize} from './column-resize';
6+
7+
@Injectable()
8+
export abstract class ResizeStrategy {
9+
abstract applyColumnSize(
10+
cssFriendlyColumnName: string,
11+
columnHeader: HTMLElement,
12+
sizeInPx: number): void;
13+
}
14+
15+
/**
16+
* The optimially performing resize strategy for &lt;table&gt; elements with table-layout: fixed.
17+
* Tested against and outperformed:
18+
* CSS selector
19+
* CSS selector w/ CSS variable
20+
* Updating all cell nodes
21+
*/
22+
@Injectable()
23+
export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
24+
applyColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number): void {
25+
columnHeader.style.boxSizing = 'border-box';
26+
columnHeader.style.width = coerceCssPixelValue(sizeInPx);
27+
}
28+
}
29+
30+
/**
31+
* The optimally performing resize strategy for flex mat-tables.
32+
* Tested against and outperformed:
33+
* CSS selector w/ CSS variable
34+
* Updating all mat-cell nodes
35+
*/
36+
@Injectable()
37+
export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDestroy {
38+
private readonly _document: Document;
39+
private readonly _columnIndexes = new Map<string, number>();
40+
41+
private _styleElement?: HTMLStyleElement;
42+
private _indexSequence = 0;
43+
44+
constructor(
45+
private readonly _columnResize: ColumnResize,
46+
@Inject(DOCUMENT) document: any) {
47+
super();
48+
this._document = document;
49+
}
50+
51+
applyColumnSize(cssFriendlyColumnName: string, _: HTMLElement, sizeInPx: number): void {
52+
let index = this._columnIndexes.get(cssFriendlyColumnName);
53+
if (index === undefined) {
54+
index = this._indexSequence++;
55+
this._columnIndexes.set(cssFriendlyColumnName, index);
56+
}
57+
58+
if (!this._styleElement) {
59+
this._styleElement = this._document.createElement('style');
60+
this._styleElement.appendChild(this._document.createTextNode(''));
61+
this._document.head.appendChild(this._styleElement);
62+
} else {
63+
(this._styleElement.sheet as CSSStyleSheet).deleteRule(index);
64+
}
65+
66+
const columnClassName = this.getColumnCssClass(cssFriendlyColumnName);
67+
const tableClassName = this._columnResize.getIdClass();
68+
69+
const selector = `.${tableClassName} .${columnClassName}`;
70+
const cssSize = coerceCssPixelValue(sizeInPx);
71+
72+
(this._styleElement.sheet as CSSStyleSheet).insertRule(
73+
`${selector} {box-sizing: border-box;flex:0 0 ${cssSize}}`, index!);
74+
}
75+
76+
protected getColumnCssClass(cssFriendlyColumnName: string): string {
77+
return `cdk-column-${cssFriendlyColumnName}`;
78+
}
79+
80+
ngOnDestroy() {
81+
// TODO: Use remove() once we're off IE11.
82+
if (this._styleElement && this._styleElement.parentNode) {
83+
this._styleElement.parentNode.removeChild(this._styleElement);
84+
this._styleElement = undefined;
85+
}
86+
}
87+
}
88+
89+
export const TABLE_LAYOUT_FIXED_RESIZE_STRATEGY_PROVIDER: Provider = {
90+
provide: ResizeStrategy,
91+
useClass: TableLayoutFixedResizeStrategy,
92+
};
93+
export const FLEX_RESIZE_STRATEGY_PROVIDER: Provider = {
94+
provide: ResizeStrategy,
95+
useClass: CdkFlexTableResizeStrategy,
96+
};

src/dev-app/column-resize/column-resize-demo-module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ import {ColumnResizeHome} from './column-resize-home';
1414
import {
1515
DefaultEnabledColumnResizeDemoModule
1616
} from './default-enabled/default-enabled-column-resize-demo-module';
17+
import {
18+
DefaultEnabledColumnResizeFlexDemoModule
19+
} from './default-enabled-flex/default-enabled-column-resize-flex-demo-module';
1720

1821
@NgModule({
1922
imports: [
2023
MatExpansionModule,
2124
DefaultEnabledColumnResizeDemoModule,
25+
DefaultEnabledColumnResizeFlexDemoModule,
2226
RouterModule.forChild([{path: '', component: ColumnResizeHome}]),
2327
],
2428
declarations: [ColumnResizeHome],
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<mat-expansion-panel>
2+
<mat-expansion-panel-header>
3+
<mat-panel-title>
4+
Enabled-by-default column resize for MatTable
5+
</mat-panel-title>
6+
</mat-expansion-panel-header>
7+
8+
<default-enabled-column-resize-demo></default-enabled-column-resize-demo>
9+
</mat-expansion-panel>
10+
11+
<mat-expansion-panel>
12+
<mat-expansion-panel-header>
13+
<mat-panel-title>
14+
Enabled-by-default column resize for flex MatTable
15+
</mat-panel-title>
16+
</mat-expansion-panel-header>
17+
18+
<default-enabled-column-resize-flex-demo></default-enabled-column-resize-flex-demo>
19+
</mat-expansion-panel>

0 commit comments

Comments
 (0)