@@ -20,6 +20,7 @@ import {
20
20
_ViewRepeaterOperation ,
21
21
} from '@angular/cdk/collections' ;
22
22
import { Platform } from '@angular/cdk/platform' ;
23
+ import { ViewportRuler } from '@angular/cdk/scrolling' ;
23
24
import { DOCUMENT } from '@angular/common' ;
24
25
import {
25
26
AfterContentChecked ,
@@ -187,8 +188,10 @@ export interface RenderRow<T> {
187
188
selector : 'cdk-table, table[cdk-table]' ,
188
189
exportAs : 'cdkTable' ,
189
190
template : CDK_TABLE_TEMPLATE ,
191
+ styleUrls : [ 'table.css' ] ,
190
192
host : {
191
193
'class' : 'cdk-table' ,
194
+ '[class.cdk-table-fixed-layout]' : 'fixedLayout' ,
192
195
} ,
193
196
encapsulation : ViewEncapsulation . None ,
194
197
// The "OnPush" status for the `MatTable` component is effectively a noop, so we are removing it.
@@ -290,6 +293,19 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
290
293
*/
291
294
private _footerRowDefChanged = true ;
292
295
296
+ /**
297
+ * Whether the sticky column styles need to be updated. Set to `true` when the visible columns
298
+ * change.
299
+ */
300
+ private _stickyColumnStylesNeedReset = true ;
301
+
302
+ /**
303
+ * Whether the sticky styler should recalculate cell widths when applying sticky styles. If
304
+ * `false`, cached values will be used instead. This is only applicable to tables with
305
+ * {@link fixedLayout} enabled. For other tables, cell widths will always be recalculated.
306
+ */
307
+ private _forceRecalculateCellWidths = true ;
308
+
293
309
/**
294
310
* Cache of the latest rendered `RenderRow` objects as a map for easy retrieval when constructing
295
311
* a new list of `RenderRow` objects for rendering rows. Since the new list is constructed with
@@ -401,6 +417,23 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
401
417
}
402
418
_multiTemplateDataRows : boolean = false ;
403
419
420
+ /**
421
+ * Whether to use a fixed table layout. Enabling this option will enforce consistent column widths
422
+ * and optimize rendering sticky styles for native tables. No-op for flex tables.
423
+ */
424
+ @Input ( )
425
+ get fixedLayout ( ) : boolean {
426
+ return this . _fixedLayout ;
427
+ }
428
+ set fixedLayout ( v : boolean ) {
429
+ this . _fixedLayout = coerceBooleanProperty ( v ) ;
430
+
431
+ // Toggling `fixedLayout` may change column widths. Sticky column styles should be recalculated.
432
+ this . _forceRecalculateCellWidths = true ;
433
+ this . _stickyColumnStylesNeedReset = true ;
434
+ }
435
+ private _fixedLayout : boolean = false ;
436
+
404
437
// TODO(andrewseguin): Remove max value as the end index
405
438
// and instead calculate the view on init and scroll.
406
439
/**
@@ -450,7 +483,11 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
450
483
// Optional for backwards compatibility, but a view repeater strategy will always
451
484
// be provided.
452
485
@Optional ( ) @Inject ( _VIEW_REPEATER_STRATEGY )
453
- protected readonly _viewRepeater : _ViewRepeater < T , RenderRow < T > , RowContext < T > > ) {
486
+ protected readonly _viewRepeater : _ViewRepeater < T , RenderRow < T > , RowContext < T > > ,
487
+ // Optional for backwards compatibility. The viewport ruler is provided in root. Therefore,
488
+ // this property will never be null.
489
+ // tslint:disable-next-line: lightweight-tokens
490
+ @Optional ( ) private readonly _viewportRuler : ViewportRuler ) {
454
491
if ( ! role ) {
455
492
this . _elementRef . nativeElement . setAttribute ( 'role' , 'grid' ) ;
456
493
}
@@ -472,6 +509,12 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
472
509
this . _dataDiffer = this . _differs . find ( [ ] ) . create ( ( _i : number , dataRow : RenderRow < T > ) => {
473
510
return this . trackBy ? this . trackBy ( dataRow . dataIndex , dataRow . data ) : dataRow ;
474
511
} ) ;
512
+
513
+ // Table cell dimensions may change after resizing the window. Signal the sticky styler to
514
+ // refresh its cache of cell widths the next time sticky styles are updated.
515
+ this . _viewportRuler . change ( ) . pipe ( takeUntil ( this . _onDestroy ) ) . subscribe ( ( ) => {
516
+ this . _forceRecalculateCellWidths = true ;
517
+ } ) ;
475
518
}
476
519
477
520
ngAfterContentChecked ( ) {
@@ -487,8 +530,10 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
487
530
488
531
// Render updates if the list of columns have been changed for the header, row, or footer defs.
489
532
const columnsChanged = this . _renderUpdatedColumns ( ) ;
490
- const stickyColumnStyleUpdateNeeded =
491
- columnsChanged || this . _headerRowDefChanged || this . _footerRowDefChanged ;
533
+ const rowDefsChanged = columnsChanged || this . _headerRowDefChanged || this . _footerRowDefChanged ;
534
+ // Ensure sticky column styles are reset if set to `true` elsewhere.
535
+ this . _stickyColumnStylesNeedReset = this . _stickyColumnStylesNeedReset || rowDefsChanged ;
536
+ this . _forceRecalculateCellWidths = rowDefsChanged ;
492
537
493
538
// If the header row definition has been changed, trigger a render to the header row.
494
539
if ( this . _headerRowDefChanged ) {
@@ -506,7 +551,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
506
551
// connection has already been made.
507
552
if ( this . dataSource && this . _rowDefs . length > 0 && ! this . _renderChangeSubscription ) {
508
553
this . _observeRenderChanges ( ) ;
509
- } else if ( stickyColumnStyleUpdateNeeded ) {
554
+ } else if ( this . _stickyColumnStylesNeedReset ) {
510
555
// In the above case, _observeRenderChanges will result in updateStickyColumnStyles being
511
556
// called when it row data arrives. Otherwise, we need to call it proactively.
512
557
this . updateStickyColumnStyles ( ) ;
@@ -688,10 +733,18 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
688
733
const dataRows = this . _getRenderedRows ( this . _rowOutlet ) ;
689
734
const footerRows = this . _getRenderedRows ( this . _footerRowOutlet ) ;
690
735
691
- // Clear the left and right positioning from all columns in the table across all rows since
692
- // sticky columns span across all table sections (header, data, footer)
693
- this . _stickyStyler . clearStickyPositioning (
694
- [ ...headerRows , ...dataRows , ...footerRows ] , [ 'left' , 'right' ] ) ;
736
+ // For tables not using a fixed layout, the column widths may change when new rows are rendered.
737
+ // In a table using a fixed layout, row content won't affect column width, so sticky styles
738
+ // don't need to be cleared unless either the sticky column config changes or one of the row
739
+ // defs change.
740
+ if ( ( this . _isNativeHtmlTable && ! this . _fixedLayout )
741
+ || this . _stickyColumnStylesNeedReset ) {
742
+ // Clear the left and right positioning from all columns in the table across all rows since
743
+ // sticky columns span across all table sections (header, data, footer)
744
+ this . _stickyStyler . clearStickyPositioning (
745
+ [ ...headerRows , ...dataRows , ...footerRows ] , [ 'left' , 'right' ] ) ;
746
+ this . _stickyColumnStylesNeedReset = false ;
747
+ }
695
748
696
749
// Update the sticky styles for each header row depending on the def's sticky state
697
750
headerRows . forEach ( ( headerRow , i ) => {
@@ -936,7 +989,9 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
936
989
} ) ;
937
990
const stickyStartStates = columnDefs . map ( columnDef => columnDef . sticky ) ;
938
991
const stickyEndStates = columnDefs . map ( columnDef => columnDef . stickyEnd ) ;
939
- this . _stickyStyler . updateStickyColumns ( rows , stickyStartStates , stickyEndStates ) ;
992
+ this . _stickyStyler . updateStickyColumns (
993
+ rows , stickyStartStates , stickyEndStates ,
994
+ ! this . _fixedLayout || this . _forceRecalculateCellWidths ) ;
940
995
}
941
996
942
997
/** Gets the list of rows that have been rendered in the row outlet. */
@@ -1115,6 +1170,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
1115
1170
}
1116
1171
1117
1172
if ( Array . from ( this . _columnDefsByName . values ( ) ) . reduce ( stickyCheckReducer , false ) ) {
1173
+ this . _stickyColumnStylesNeedReset = true ;
1118
1174
this . updateStickyColumnStyles ( ) ;
1119
1175
}
1120
1176
}
@@ -1156,6 +1212,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
1156
1212
}
1157
1213
1158
1214
static ngAcceptInputType_multiTemplateDataRows : BooleanInput ;
1215
+ static ngAcceptInputType_fixedLayout : BooleanInput ;
1159
1216
}
1160
1217
1161
1218
/** Utility function that gets a merged list of the entries in an array and values of a Set. */
0 commit comments