Skip to content

Commit 6499ccb

Browse files
andrewseguinmmalerba
authored andcommitted
Table docs (#5449)
* docs(table): initial table docs * add filtering msg * add overview * fix height * split cdk table into guide * revisions * add to examples * fix heading * example changes * lint * example style prefix, rename file * newline
1 parent 05302b8 commit 6499ccb

26 files changed

+1382
-15
lines changed

guides/cdk-table.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
The `<cdk-table>` is an unopinionated, customizable data-table with a fully-templated API, dynamic
2+
columns, and an accessible DOM structure. This component acts as the core upon which anyone can
3+
build their own tailored data-table experience.
4+
5+
The table provides a foundation upon which other features, such as sorting and pagination, can be
6+
built. Because it enforces no opinions on these matters, developers have full control over the
7+
interaction patterns associated with the table.
8+
9+
For a Material Design styled table, see the documentation for `<md-table>` which builds on top of
10+
the CDK data-table.
11+
12+
<!-- example(cdk-table-basic) -->
13+
14+
### Using the CDK data-table
15+
16+
#### Writing your table template
17+
18+
The first step to writing the data-table template is to define the columns.
19+
A column definition is specified via an `<ng-container>` with the `cdkColumnDef` directive, giving
20+
column a name. Each column definition then further defines both a header-cell template
21+
(`cdkHeaderCellDef`) and a data-cell template (`cdkCellDef`).
22+
23+
24+
```html
25+
<ng-container cdkColumnDef="username">
26+
<cdk-header-cell *cdkHeaderCellDef> User name </cdk-header-cell>
27+
<cdk-cell *cdkCellDef="let row"> {{row.a}} </cdk-cell>
28+
</ng-container>
29+
```
30+
31+
The set of columns defined represent the columns that are _available_ to be rendered. The specific
32+
columns rendered in a given row, and their order, are specified on the row (see below).
33+
34+
Note that `cdkCellDef` exports the row context such that the row data can be referenced in the cell
35+
template. The directive also exports the same properties as `ngFor` (index, even, odd, first,
36+
last).
37+
38+
The next step is to define the table's header-row (`cdkHeaderRowDef`) and data-row (`cdkRowDef`).
39+
40+
```html
41+
<cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></cdk-header-row>
42+
<cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></cdk-row>
43+
```
44+
45+
These row templates accept the specific columns to be rendered via the name given to the
46+
`cdkColumnDef`.
47+
48+
49+
The `cdkRowDef` also exports row context, which can be used for event and property
50+
bindings on the row element. Any content placed _inside_ of the header row or data row template
51+
will be ignored, as the rendered content of the row comes from the cell templates described
52+
above.
53+
54+
55+
##### Example: table with three columns
56+
```html
57+
<cdk-table [dataSource]="dataSource">
58+
<!-- User name Definition -->
59+
<ng-container cdkColumnDef="username">
60+
<cdk-header-cell *cdkHeaderCellDef> User name </cdk-header-cell>
61+
<cdk-cell *cdkCellDef="let row"> {{row.username}} </cdk-cell>
62+
</ng-container>
63+
64+
<!-- Age Definition -->
65+
<ng-container cdkColumnDef="age">
66+
<cdk-header-cell *cdkHeaderCellDef> Age </cdk-header-cell>
67+
<cdk-cell *cdkCellDef="let row"> {{row.age}} </cdk-cell>
68+
</ng-container>
69+
70+
<!-- Title Definition -->
71+
<ng-container cdkColumnDef="title">
72+
<cdk-header-cell *cdkHeaderCellDef> Title </cdk-header-cell>
73+
<cdk-cell *cdkCellDef="let row"> {{row.title}} </cdk-cell>
74+
</ng-container>
75+
76+
<!-- Header and Row Declarations -->
77+
<cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></cdk-header-row>
78+
<cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></cdk-row>
79+
</cdk-table>
80+
```
81+
82+
The columns given on the row determine which cells are rendered and in which order. Thus, the
83+
columns can be set via binding to support dynamically changing the columns shown at run-time.
84+
85+
86+
It is not required to display all the columns that are defined within the template,
87+
nor use the same ordering. For example, to display the table with only `age`
88+
and `username` and in that order, then the row and header definitions would be written as:
89+
90+
```html
91+
<cdk-row *cdkRowDef="let row; columns: myDisplayedColumns"></cdk-row>
92+
```
93+
94+
Event and property bindings can be added directly to the row element.
95+
96+
##### Example: table with event and class binding
97+
```html
98+
<cdk-header-row *cdkHeaderRowDef="['age', 'username']"
99+
(click)=”handleHeaderRowClick(row)”>
100+
</cdk-header-row>
101+
102+
<cdk-row *cdkRowDef="let row; columns: ['age', 'username']"
103+
[class.can-vote]=”row.age >= 18”
104+
(click)=”handleRowClick(row)”>
105+
</cdk-row>
106+
```
107+
108+
#### Connecting the table to a data source
109+
Data is provided to the table through a `DataSource`. When the table receives a data source,
110+
it calls the DataSource's connect function which returns an observable that emits an array of data.
111+
Whenever the data source emits data to this stream, the table will update.
112+
113+
Because the _data source_ provides this stream, it bears the responsibility of triggering table
114+
updates. This can be based on _anything_: websocket connections, user interaction, model updates,
115+
time-based intervals, etc. Most commonly, updates will be triggered by user interactions like
116+
sorting and pagination.
117+
118+
##### `trackBy`
119+
To improve performance, a trackBy function can be provided to the table similar to Angular’s
120+
(`ngFor` trackBy)[trackBy]. This informs the table how to uniquely identify rows to track how the
121+
data changes with each update.
122+
123+
```html
124+
<cdk-table [dataSource]="dataSource" [trackBy]="myTrackById">
125+
```
126+
127+
128+
[trackBy][https://angular.io/api/common/NgForOf#change-propagation]

src/demo-app/table/table-demo.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ <h3>CdkTable Example</h3>
7676
<cdk-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </cdk-cell>
7777
</ng-container>
7878

79-
<cdk-header-row *cdkHeaderRowDef="propertiesToDisplay"></cdk-header-row>
80-
<cdk-row *cdkRowDef="let row; columns: propertiesToDisplay;
79+
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
80+
<cdk-row *cdkRowDef="let row; columns: displayedColumns;
8181
let first = first; let last = last; let even = even; let odd = odd"
8282
[ngClass]="{
8383
'demo-row-highlight-first': highlights.has('first') && first,
@@ -92,7 +92,7 @@ <h3>MdTable Example</h3>
9292

9393
<div class="demo-table-container demo-mat-table-example mat-elevation-z4">
9494

95-
<table-header-demo (shiftColumns)="propertiesToDisplay.push(propertiesToDisplay.shift())"
95+
<table-header-demo (shiftColumns)="displayedColumns.push(displayedColumns.shift())"
9696
(toggleColorColumn)="toggleColorColumn()">
9797
</table-header-demo>
9898

@@ -130,8 +130,8 @@ <h3>MdTable Example</h3>
130130
<md-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </md-cell>
131131
</ng-container>
132132

133-
<md-header-row *cdkHeaderRowDef="propertiesToDisplay"></md-header-row>
134-
<md-row *cdkRowDef="let row; columns: propertiesToDisplay"></md-row>
133+
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
134+
<md-row *cdkRowDef="let row; columns: displayedColumns"></md-row>
135135

136136
</md-table>
137137

src/demo-app/table/table-demo.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type TrackByStrategy = 'id' | 'reference' | 'index';
1616
})
1717
export class TableDemo {
1818
dataSource: PersonDataSource | null;
19-
propertiesToDisplay: UserProperties[] = [];
19+
displayedColumns: UserProperties[] = [];
2020
trackByStrategy: TrackByStrategy = 'reference';
2121
changeReferences = false;
2222
highlights = new Set<string>();
@@ -32,15 +32,15 @@ export class TableDemo {
3232
}
3333

3434
connect() {
35-
this.propertiesToDisplay = ['userId', 'userName', 'progress', 'color'];
35+
this.displayedColumns = ['userId', 'userName', 'progress', 'color'];
3636
this.dataSource = new PersonDataSource(this._peopleDatabase,
3737
this._paginator, this.sort);
3838
this._peopleDatabase.initialize();
3939
}
4040

4141
disconnect() {
4242
this.dataSource = null;
43-
this.propertiesToDisplay = [];
43+
this.displayedColumns = [];
4444
}
4545

4646
getOpacity(progress: number) {
@@ -57,11 +57,11 @@ export class TableDemo {
5757
}
5858

5959
toggleColorColumn() {
60-
let colorColumnIndex = this.propertiesToDisplay.indexOf('color');
60+
let colorColumnIndex = this.displayedColumns.indexOf('color');
6161
if (colorColumnIndex == -1) {
62-
this.propertiesToDisplay.push('color');
62+
this.displayedColumns.push('color');
6363
} else {
64-
this.propertiesToDisplay.splice(colorColumnIndex, 1);
64+
this.displayedColumns.splice(colorColumnIndex, 1);
6565
}
6666
}
6767

src/lib/table/table.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
The `md-table` provides a Material Design styled data-table that can be used to display rows of
2+
data.
3+
4+
This table builds on the foundation of the CDK data-table and uses a similar interface for its
5+
data source input and template, except that its element selectors will be prefixed with `md-`
6+
instead of `cdk-`.
7+
8+
<!-- example(table-basic) -->
9+
10+
Note that the column definition directives (`cdkColumnDef` and `cdkHeaderCellDef`) are still
11+
prefixed with `cdk-`.
12+
13+
For more information on the interface and how it works, see the guide covering the CDK data-table.
14+
15+
### Features
16+
17+
The `<md-table>` itself only deals with the rendering of a table structure (rows and cells).
18+
Additional features can be built on top of the table by adding behavior inside cell templates
19+
(e.g., sort headers) or next to the table (e.g. a paginator). Interactions that affect the
20+
rendered data (such as sorting and pagination) should be propagated through the table's data source.
21+
22+
23+
#### Pagination
24+
25+
The `<md-paginator>` adds a pagination UI that can be used in conjunction with the `<md-table>`. The
26+
paginator emits events that can be used to trigger an update via the table's data source.
27+
28+
<!-- example(table-pagination) -->
29+
30+
#### Sorting
31+
Use the `mdSort` directive and `<md-sort-header>` adds a sorting UI the table's column headers. The
32+
sort headers emit events that can be used to trigger an update via the table's data source.
33+
34+
<!-- example(table-sorting) -->
35+
36+
#### Filtering
37+
38+
While Angular Material does not offer a specific component for filtering tabular data, the table's
39+
data source can be updated based on any custom filter UI. Any filtering pattern need only trigger
40+
an update via the table's data source.
41+
42+
43+
<!--- example(table-filtering) -->
44+
45+
### Simple Table
46+
47+
In the near future, we will provide a simplified version of the data-table with an easy-to-use
48+
interface, material styling, array input, and more out-of-the-box features (sorting, pagination,
49+
and selection).
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* Structure */
2+
.example-container {
3+
display: flex;
4+
flex-direction: column;
5+
max-height: 500px;
6+
min-width: 300px;
7+
}
8+
9+
/*
10+
* Styles to make the demo's cdk-table match the material design spec
11+
* https://material.io/guidelines/components/data-tables.html
12+
*/
13+
.example-table {
14+
flex: 1 1 auto;
15+
overflow: auto;
16+
}
17+
18+
.example-header-row, .example-row {
19+
display: flex;
20+
border-bottom: 1px solid #ccc;
21+
align-items: center;
22+
height: 32px;
23+
padding: 0 8px;
24+
}
25+
26+
.example-cell, .example-header-cell {
27+
flex: 1;
28+
}
29+
30+
.example-header-cell {
31+
font-size: 12px;
32+
font-weight: bold;
33+
color: rgba(0, 0, 0, 0.54);
34+
}
35+
36+
.example-cell {
37+
font-size: 13px;
38+
color: rgba(0, 0, 0, 0.87);
39+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<div class="example-container mat-elevation-z8">
2+
<cdk-table #table [dataSource]="dataSource" class="example-table">
3+
<!--- Note that these columns can be defined in any order.
4+
The actual rendered columns are set as a property on the row definition" -->
5+
6+
<!-- ID Column -->
7+
<ng-container cdkColumnDef="userId">
8+
<cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> ID </cdk-header-cell>
9+
<cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.id}} </cdk-cell>
10+
</ng-container>
11+
12+
<!-- Progress Column -->
13+
<ng-container cdkColumnDef="progress">
14+
<cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Progress </cdk-header-cell>
15+
<cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.progress}}% </cdk-cell>
16+
</ng-container>
17+
18+
<!-- Name Column -->
19+
<ng-container cdkColumnDef="userName">
20+
<cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Name </cdk-header-cell>
21+
<cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.name}} </cdk-cell>
22+
</ng-container>
23+
24+
<!-- Color Column -->
25+
<ng-container cdkColumnDef="color">
26+
<cdk-header-cell *cdkHeaderCellDef class="example-header-cell">Color</cdk-header-cell>
27+
<cdk-cell *cdkCellDef="let row" class="example-cell"
28+
[style.color]="row.color">
29+
{{row.color}}
30+
</cdk-cell>
31+
</ng-container>
32+
33+
<cdk-header-row *cdkHeaderRowDef="displayedColumns" class="example-header-row"></cdk-header-row>
34+
<cdk-row *cdkRowDef="let row; columns: displayedColumns;" class="example-row"></cdk-row>
35+
</cdk-table>
36+
</div>

0 commit comments

Comments
 (0)