@@ -18,12 +18,17 @@ import {ColumnResize} from './column-resize';
1818 * The details of how resizing works for tables for flex mat-tables are quite different.
1919 */
2020@Injectable ( )
21- export abstract class ResizeStrategy {
21+ export abstract class ResizeStrategy implements OnDestroy {
2222 protected abstract readonly columnResize : ColumnResize ;
2323 protected abstract readonly styleScheduler : _CoalescedStyleScheduler ;
2424 protected abstract readonly table : CdkTable < unknown > ;
2525
2626 private _pendingResizeDelta : number | null = null ;
27+ private _tableObserved = false ;
28+ private _elemSizeCache = new WeakMap < HTMLElement , { width : number ; height : number } > ( ) ;
29+ private _resizeObserver = globalThis ?. ResizeObserver
30+ ? new globalThis . ResizeObserver ( entries => this . _updateCachedSizes ( entries ) )
31+ : null ;
2732
2833 /** Updates the width of the specified column. */
2934 abstract applyColumnSize (
@@ -51,7 +56,7 @@ export abstract class ResizeStrategy {
5156 protected updateTableWidthAndStickyColumns ( delta : number ) : void {
5257 if ( this . _pendingResizeDelta === null ) {
5358 const tableElement = this . columnResize . elementRef . nativeElement ;
54- const tableWidth = getElementWidth ( tableElement ) ;
59+ const tableWidth = this . getElementWidth ( tableElement ) ;
5560
5661 this . styleScheduler . schedule ( ( ) => {
5762 tableElement . style . width = coerceCssPixelValue ( tableWidth + this . _pendingResizeDelta ! ) ;
@@ -66,6 +71,48 @@ export abstract class ResizeStrategy {
6671
6772 this . _pendingResizeDelta = ( this . _pendingResizeDelta ?? 0 ) + delta ;
6873 }
74+
75+ /** Gets the style.width pixels on the specified element if present, otherwise its offsetWidth. */
76+ protected getElementWidth ( element : HTMLElement ) {
77+ // Optimization: Check style.width first as we probably set it already before reading
78+ // offsetWidth which triggers layout.
79+ return (
80+ coercePixelsFromCssValue ( element . style . width ) ||
81+ this . _elemSizeCache . get ( element ) ?. width ||
82+ element . offsetWidth
83+ ) ;
84+ }
85+
86+ /** Informs the ResizeStrategy instance of a column that may be resized in the future. */
87+ registerColumn ( column : HTMLElement ) {
88+ if ( ! this . _tableObserved ) {
89+ this . _tableObserved = true ;
90+ this . _resizeObserver ?. observe ( this . columnResize . elementRef . nativeElement , {
91+ box : 'border-box' ,
92+ } ) ;
93+ }
94+ this . _resizeObserver ?. observe ( column , { box : 'border-box' } ) ;
95+ }
96+
97+ ngOnDestroy ( ) : void {
98+ this . _resizeObserver ?. disconnect ( ) ;
99+ }
100+
101+ private _updateCachedSizes ( entries : ResizeObserverEntry [ ] ) {
102+ for ( const entry of entries ) {
103+ const newEntry = entry . borderBoxSize ?. length
104+ ? {
105+ width : entry . borderBoxSize [ 0 ] . inlineSize ,
106+ height : entry . borderBoxSize [ 0 ] . blockSize ,
107+ }
108+ : {
109+ width : entry . contentRect . width ,
110+ height : entry . contentRect . height ,
111+ } ;
112+
113+ this . _elemSizeCache . set ( entry . target as HTMLElement , newEntry ) ;
114+ }
115+ }
69116}
70117
71118/**
@@ -87,7 +134,7 @@ export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
87134 sizeInPx : number ,
88135 previousSizeInPx ?: number ,
89136 ) : void {
90- const delta = sizeInPx - ( previousSizeInPx ?? getElementWidth ( columnHeader ) ) ;
137+ const delta = sizeInPx - ( previousSizeInPx ?? this . getElementWidth ( columnHeader ) ) ;
91138
92139 if ( delta === 0 ) {
93140 return ;
@@ -101,14 +148,14 @@ export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
101148 }
102149
103150 applyMinColumnSize ( _ : string , columnHeader : HTMLElement , sizeInPx : number ) : void {
104- const currentWidth = getElementWidth ( columnHeader ) ;
151+ const currentWidth = this . getElementWidth ( columnHeader ) ;
105152 const newWidth = Math . max ( currentWidth , sizeInPx ) ;
106153
107154 this . applyColumnSize ( _ , columnHeader , newWidth , currentWidth ) ;
108155 }
109156
110157 applyMaxColumnSize ( _ : string , columnHeader : HTMLElement , sizeInPx : number ) : void {
111- const currentWidth = getElementWidth ( columnHeader ) ;
158+ const currentWidth = this . getElementWidth ( columnHeader ) ;
112159 const newWidth = Math . min ( currentWidth , sizeInPx ) ;
113160
114161 this . applyColumnSize ( _ , columnHeader , newWidth , currentWidth ) ;
@@ -189,7 +236,8 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest
189236 return `cdk-column-${ cssFriendlyColumnName } ` ;
190237 }
191238
192- ngOnDestroy ( ) : void {
239+ override ngOnDestroy ( ) : void {
240+ super . ngOnDestroy ( ) ;
193241 this . _styleElement ?. remove ( ) ;
194242 this . _styleElement = undefined ;
195243 }
@@ -277,13 +325,6 @@ function coercePixelsFromCssValue(cssValue: string): number {
277325 return Number ( cssValue . match ( / ( \d + ) p x / ) ?. [ 1 ] ) ;
278326}
279327
280- /** Gets the style.width pixels on the specified element if present, otherwise its offsetWidth. */
281- function getElementWidth ( element : HTMLElement ) {
282- // Optimization: Check style.width first as we probably set it already before reading
283- // offsetWidth which triggers layout.
284- return coercePixelsFromCssValue ( element . style . width ) || element . offsetWidth ;
285- }
286-
287328/**
288329 * Converts CSS flex values as set in CdkFlexTableResizeStrategy to numbers,
289330 * eg "0 0.01 123px" to 123.
0 commit comments