Skip to content

Commit 6df3709

Browse files
authored
feat(table): add optional footer row (#10330)
1 parent a0c77e2 commit 6df3709

File tree

17 files changed

+942
-532
lines changed

17 files changed

+942
-532
lines changed

src/cdk/table/cell.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88

99
import {ContentChild, Directive, ElementRef, Input, TemplateRef} from '@angular/core';
1010

11+
/** Base interface for a cell definition. Captures a column's cell template definition. */
12+
export interface CellDef {
13+
template: TemplateRef<any>;
14+
}
15+
1116
/**
1217
* Cell definition for a CDK table.
1318
* Captures the template of a column's data row cell as well as cell-specific properties.
1419
*/
1520
@Directive({selector: '[cdkCellDef]'})
16-
export class CdkCellDef {
21+
export class CdkCellDef implements CellDef {
1722
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
1823
}
1924

@@ -22,7 +27,16 @@ export class CdkCellDef {
2227
* Captures the template of a column's header cell and as well as cell-specific properties.
2328
*/
2429
@Directive({selector: '[cdkHeaderCellDef]'})
25-
export class CdkHeaderCellDef {
30+
export class CdkHeaderCellDef implements CellDef {
31+
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
32+
}
33+
34+
/**
35+
* Footer cell definition for a CDK table.
36+
* Captures the template of a column's footer cell and as well as cell-specific properties.
37+
*/
38+
@Directive({selector: '[cdkFooterCellDef]'})
39+
export class CdkFooterCellDef implements CellDef {
2640
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
2741
}
2842

@@ -51,6 +65,9 @@ export class CdkColumnDef {
5165
/** @docs-private */
5266
@ContentChild(CdkHeaderCellDef) headerCell: CdkHeaderCellDef;
5367

68+
/** @docs-private */
69+
@ContentChild(CdkFooterCellDef) footerCell: CdkFooterCellDef;
70+
5471
/**
5572
* Transformed version of the column name that can be used as part of a CSS classname. Excludes
5673
* all non-alphanumeric characters and the special characters '-' and '_'. Any characters that
@@ -59,6 +76,14 @@ export class CdkColumnDef {
5976
cssClassFriendlyName: string;
6077
}
6178

79+
/** Base class for the cells. Adds a CSS classname that identifies the column it renders in. */
80+
export class BaseCdkCell {
81+
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
82+
const columnClassName = `cdk-column-${columnDef.cssClassFriendlyName}`;
83+
elementRef.nativeElement.classList.add(columnClassName);
84+
}
85+
}
86+
6287
/** Header cell template container that adds the right classes and role. */
6388
@Directive({
6489
selector: 'cdk-header-cell, th[cdk-header-cell]',
@@ -67,9 +92,23 @@ export class CdkColumnDef {
6792
'role': 'columnheader',
6893
},
6994
})
70-
export class CdkHeaderCell {
95+
export class CdkHeaderCell extends BaseCdkCell {
96+
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
97+
super(columnDef, elementRef);
98+
}
99+
}
100+
101+
/** Footer cell template container that adds the right classes and role. */
102+
@Directive({
103+
selector: 'cdk-footer-cell, td[cdk-footer-cell]',
104+
host: {
105+
'class': 'cdk-footer-cell',
106+
'role': 'gridcell',
107+
},
108+
})
109+
export class CdkFooterCell extends BaseCdkCell {
71110
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
72-
elementRef.nativeElement.classList.add(`cdk-column-${columnDef.cssClassFriendlyName}`);
111+
super(columnDef, elementRef);
73112
}
74113
}
75114

@@ -81,8 +120,8 @@ export class CdkHeaderCell {
81120
'role': 'gridcell',
82121
},
83122
})
84-
export class CdkCell {
123+
export class CdkCell extends BaseCdkCell {
85124
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
86-
elementRef.nativeElement.classList.add(`cdk-column-${columnDef.cssClassFriendlyName}`);
125+
super(columnDef, elementRef);
87126
}
88127
}

src/cdk/table/row.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
ViewContainerRef,
1919
ViewEncapsulation,
2020
} from '@angular/core';
21-
import {CdkCellDef} from './cell';
21+
import {CdkCellDef, CdkColumnDef} from './cell';
2222

2323
/**
2424
* The row template that can be used by the mat-table. Should not be used outside of the
@@ -57,6 +57,9 @@ export abstract class BaseRowDef {
5757
getColumnsDiff(): IterableChanges<any> | null {
5858
return this._columnsDiffer.diff(this.columns);
5959
}
60+
61+
/** Gets this row def's relevant cell template from the provided column def. */
62+
abstract extractCellTemplate(column: CdkColumnDef): TemplateRef<any>;
6063
}
6164

6265
/**
@@ -71,6 +74,30 @@ export class CdkHeaderRowDef extends BaseRowDef {
7174
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
7275
super(template, _differs);
7376
}
77+
78+
/** Gets this row def's relevant cell template from the provided column def. */
79+
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
80+
return column.headerCell.template;
81+
}
82+
}
83+
84+
/**
85+
* Footer row definition for the CDK table.
86+
* Captures the footer row's template and other footer properties such as the columns to display.
87+
*/
88+
@Directive({
89+
selector: '[cdkFooterRowDef]',
90+
inputs: ['columns: cdkFooterRowDef'],
91+
})
92+
export class CdkFooterRowDef extends BaseRowDef {
93+
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
94+
super(template, _differs);
95+
}
96+
97+
/** Gets this row def's relevant cell template from the provided column def. */
98+
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
99+
return column.footerCell.template;
100+
}
74101
}
75102

76103
/**
@@ -96,12 +123,17 @@ export class CdkRowDef<T> extends BaseRowDef {
96123
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
97124
super(template, _differs);
98125
}
126+
127+
/** Gets this row def's relevant cell template from the provided column def. */
128+
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
129+
return column.cell.template;
130+
}
99131
}
100132

101133
/** Context provided to the row cells */
102134
export interface CdkCellOutletRowContext<T> {
103135
/** Data for the row that this cell is located within. */
104-
$implicit: T;
136+
$implicit?: T;
105137

106138
/** Index location of the row that this cell is located within. */
107139
index?: number;
@@ -162,6 +194,21 @@ export class CdkCellOutlet {
162194
})
163195
export class CdkHeaderRow { }
164196

197+
198+
/** Footer template container that contains the cell outlet. Adds the right class and role. */
199+
@Component({
200+
moduleId: module.id,
201+
selector: 'cdk-footer-row, tr[cdk-footer-row]',
202+
template: CDK_ROW_TEMPLATE,
203+
host: {
204+
'class': 'cdk-footer-row',
205+
'role': 'row',
206+
},
207+
changeDetection: ChangeDetectionStrategy.OnPush,
208+
encapsulation: ViewEncapsulation.None,
209+
})
210+
export class CdkFooterRow { }
211+
165212
/** Data row template container that contains the cell outlet. Adds the right class and role. */
166213
@Component({
167214
moduleId: module.id,

src/cdk/table/table-module.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,35 @@
88

99
import {CommonModule} from '@angular/common';
1010
import {NgModule} from '@angular/core';
11-
import {CdkTable, HeaderRowPlaceholder, RowPlaceholder} from './table';
12-
import {CdkCellOutlet, CdkHeaderRow, CdkHeaderRowDef, CdkRow, CdkRowDef} from './row';
13-
import {CdkCell, CdkCellDef, CdkColumnDef, CdkHeaderCell, CdkHeaderCellDef} from './cell';
11+
import {HeaderRowOutlet, DataRowOutlet, CdkTable, FooterRowOutlet} from './table';
12+
import {
13+
CdkCellOutlet, CdkFooterRow, CdkFooterRowDef, CdkHeaderRow, CdkHeaderRowDef, CdkRow,
14+
CdkRowDef
15+
} from './row';
16+
import {
17+
CdkColumnDef, CdkHeaderCellDef, CdkHeaderCell, CdkCell, CdkCellDef,
18+
CdkFooterCellDef, CdkFooterCell
19+
} from './cell';
1420

1521
const EXPORTED_DECLARATIONS = [
1622
CdkTable,
1723
CdkRowDef,
1824
CdkCellDef,
1925
CdkCellOutlet,
2026
CdkHeaderCellDef,
27+
CdkFooterCellDef,
2128
CdkColumnDef,
2229
CdkCell,
2330
CdkRow,
2431
CdkHeaderCell,
32+
CdkFooterCell,
2533
CdkHeaderRow,
2634
CdkHeaderRowDef,
27-
RowPlaceholder,
28-
HeaderRowPlaceholder,
35+
CdkFooterRow,
36+
CdkFooterRowDef,
37+
DataRowOutlet,
38+
HeaderRowOutlet,
39+
FooterRowOutlet,
2940
];
3041

3142
@NgModule({

src/cdk/table/table.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ top of the CDK data-table.
1818

1919
The first step to writing the data-table template is to define the columns.
2020
A column definition is specified via an `<ng-container>` with the `cdkColumnDef` directive, giving
21-
the column a name. Each column definition then further defines both a header-cell template
22-
(`cdkHeaderCellDef`) and a data-cell template (`cdkCellDef`).
21+
the column a name. Each column definition can contain a header-cell template
22+
(`cdkHeaderCellDef`), data-cell template (`cdkCellDef`), and footer-cell
23+
template (`cdkFooterCellDef`).
2324

2425
```html
2526
<ng-container cdkColumnDef="username">
2627
<th cdk-header-cell *cdkHeaderCellDef> User name </th>
2728
<td cdk-cell *cdkCellDef="let row"> {{row.a}} </td>
29+
<td cdk-footer-cell *cdkFooterCellDef> User name </td>
2830
</ng-container>
2931
```
3032

@@ -35,11 +37,15 @@ Note that `cdkCellDef` exports the row context such that the row data can be ref
3537
template. The directive also exports the same properties as `ngFor` (index, even, odd, first,
3638
last).
3739

38-
The next step is to define the table's header-row (`cdkHeaderRowDef`) and data-row (`cdkRowDef`).
40+
The next step is to define the table's header-row (`cdkHeaderRowDef`), data-row (`cdkRowDef`),
41+
and fitler-row (`cdkFooterRowDef`). Note that each of these are optional to include, depending on
42+
what type of rows you want rendered (e.g. if you do not need a footer row, simply do not add
43+
its definition).
3944

4045
```html
4146
<tr cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></tr>
4247
<tr cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></tr>
48+
<tr cdk-footer-row *cdkFooterRowDef="['username', 'age', 'title']"></tr>
4349
```
4450

4551
These row templates accept the specific columns to be rendered via the name given to the

0 commit comments

Comments
 (0)