-
Notifications
You must be signed in to change notification settings - Fork 6.8k
docs(table): updated docs for the table #8162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
07bb7b7
4e83d98
183c4d1
4319864
fe31df8
9b7e82a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,185 @@ | ||
The `mat-table` provides a Material Design styled data-table that can be used to display rows of | ||
data. | ||
The `mat-table` provides a Material Design styled data-table that can be used to display rows of | ||
data. | ||
|
||
The table's template is made up of column definitions where each definition provides the content for | ||
that column's header and row cells. It also includes a `<mat-header-row>` and `<mat-row>` where each | ||
takes an ordered list of the columns they should render. | ||
|
||
Passing data to the table must be done through a `DataSource`, which connects to the table by | ||
providing an Observable that emits an array of data. The table picks up this data array and writes | ||
a `mat-row` for each data object in the array. It is the responsibility of the `DataSource` to send | ||
exactly what data should be rendered by the table, so any data manipulation features such as | ||
sorting or filtering should be implemented here. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trying to tighten the language a bit, avoiding passive voice: A `DataSource` provides data to the table by emitting an `Observable` stream of
the items to be rendered. Each emit includes the _entire set of items_ that being
displayed. The table, listening to this stream, will render a row per item. Any
manipulation of the data being displayed (e.g. sorting, pagination, filtering)
should be captured by the `DataSource`, ultimately emitting a new set of
items to reflect any changes. |
||
|
||
This table builds on the foundation of the CDK data-table and uses a similar interface for its | ||
data source input and template, except that its element and attribute selectors will be prefixed | ||
with `mat-` instead of `cdk-`. | ||
|
||
For more information on the interface and how it works, see the | ||
with `mat-` instead of `cdk-`. For detailed information on the interface and how it works, see the | ||
[guide covering the CDK data-table](https://material.angular.io/guide/cdk-table). | ||
|
||
### Getting Started | ||
|
||
<!-- example(table-basic) --> | ||
|
||
### Features | ||
Start by writing your table's column definitions. Each column definition should be given a unique | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would numbered subheaders help here? #### 1. Define the table's columns
...
#### 2. Define the table's rows
...
#### 3. Provide data
... |
||
name and contain the content definitions for its header and row cells. | ||
|
||
Here's a simple column definition with the name `'userName'`. The header cell contains the text | ||
"Name" and each row cell will render the `name` property of each row's data. | ||
|
||
```html | ||
<ng-container matColumnDef="userName"> | ||
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell> | ||
<mat-cell *matCellDef="let user"> {{user.name}} </mat-cell> | ||
</ng-container> | ||
``` | ||
|
||
After you define all your columns, you'll need to provide the header and data row templates that | ||
will be rendered out by the table. Each template should be given an ordered list of columns that | ||
will let the table know what columns each row should render. | ||
|
||
```html | ||
<mat-header-row *matHeaderRowDef="['userName', 'age']"></mat-header-row> | ||
<mat-row *matRowDef="let myRowData; columns: ['userName', 'age']"></mat-row> | ||
``` | ||
|
||
Once your template is set up, the final step is to provide data to the table. This must be done | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe something like The column and row definitions now capture _how_ data will render- all that's
left is to provide the data itself. For simple scenarios with client-side operations,
`MatTableDataSource` offers a quick and easy starting point. Simply create an
instance of `MatTableDataSource` and set the items to be displayed to the
`data` property. For more advanced scenarios, applications will implement
one or more custom `DataSource` to capture more specific behaviors. |
||
through a `DataSource`, which uses an Observable stream that emits an array of data that the table | ||
should render. | ||
|
||
To get started, you can use the pre-built `MatTableDataSource` to handle the stream for you. | ||
Just create a new instance and set its `data` property to whatever data you want the table to | ||
render. | ||
|
||
The `<mat-table>` itself only deals with the rendering of a table structure (rows and cells). | ||
Additional features can be built on top of the table by adding behavior inside cell templates | ||
(e.g., sort headers) or next to the table (e.g. a paginator). Interactions that affect the | ||
rendered data (such as sorting and pagination) should be propagated through the table's data source. | ||
```ts | ||
this.myDataSource = new MatTableDataSource(); | ||
this.myDataSource.data = dataToRender; | ||
``` | ||
|
||
```html | ||
<mat-table [dataSource]=”myDataSource”> | ||
... | ||
</mat-table> | ||
``` | ||
|
||
### Features | ||
|
||
#### Pagination | ||
|
||
The `<mat-paginator>` adds a pagination UI that can be used in conjunction with the `<mat-table>`. The | ||
paginator emits events that can be used to trigger an update via the table's data source. | ||
To paginate the table's data, add a `<mat-paginator>` after the `<mat-table>` and provide the | ||
`MatPaginator` to the `MatTableDataSource`. The data source will automatically listen for page | ||
changes made by the user and send the right paged data to the table. | ||
|
||
For more information on using and configuring the `<mat-paginator>`, check out the | ||
[mat-paginator docs](https://material.angular.io/components/paginator/overview). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should mention here that (same for sorting, filtering, and selection) |
||
|
||
<!-- example(table-pagination) --> | ||
|
||
#### Sorting | ||
|
||
Use the `matSort` directive and `<mat-sort-header>` adds a sorting UI the table's column headers. The | ||
sort headers emit events that can be used to trigger an update via the table's data source. | ||
To add sorting behavior to the table, add the `matSort` directive to the `<mat-table>` and add | ||
`mat-sort-header` to each column header cell that should trigger sorting. Provide the `MatSort` | ||
directive to the `MatTableDataSource` and it will automatically listen for sorting changes and | ||
change the order of data rendered by the table. | ||
|
||
By default, the `MatTableDataSource` sorts with the assumption that the sorted column's name | ||
matches the data property name that the column displays. For example, the following column | ||
definition is named `position`, which matches the name of the property displayed in the row cell. | ||
|
||
```html | ||
<!-- Name Column --> | ||
<ng-container matColumnDef="position"> | ||
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> | ||
<mat-cell *matCellDef="let element"> {{element.position}} </mat-cell> | ||
</ng-container> | ||
``` | ||
|
||
If the data properties do not match the column names, or if a more complex data property accessor | ||
is required, then a custom `sortingDataAccessor` function can be set to override the default data | ||
accessor on the `MatTableDataSource`. | ||
|
||
<!-- example(table-sorting) --> | ||
|
||
For more information on using and configuring the sorting behavior, check out the | ||
[matSort docs](https://material.angular.io/components/sort/overview). | ||
|
||
#### Filtering | ||
|
||
While Angular Material does not offer a specific component for filtering tabular data, the table's | ||
data source can be updated based on any custom filter UI. Any filtering pattern need only trigger | ||
an update via the table's data source. | ||
To remove filtered rows from the table's data, simply provide the filter string to the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is too specifically about the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Flexibility is great, but this documentation is under angular/material2. Most developers won't have time to try a lot of different options. Would still be good to provide example code for MatTableDataSource. |
||
`MatTableDataSource`. The data source will reduce each row data to a serialized form and will | ||
filter out the row if it does not contain the filter string. By default, the row data reducing | ||
function will concatenate all the object values and convert them to lowercase. | ||
|
||
<!--- example(table-filtering) --> | ||
For example, the data object `{id: 123, name: 'Mr. Smith', favoriteColor: 'blue'}` will be | ||
reduced to `123mr. smithblue`. If your filter string was `blue` then it would be considered a match | ||
because it is contained in the reduced string, and the row would be displayed in the table. | ||
|
||
### Simple Table | ||
To override the default filtering behavior, a custom `filterPredicate` function can be set | ||
which takes a data object and filter string and returns true if the data object is considered a | ||
match. | ||
|
||
<!--- example(table-filtering) --> | ||
|
||
In the near future, we will provide a simplified version of the data-table with an easy-to-use | ||
interface, material styling, array input, and more out-of-the-box features (sorting, pagination, | ||
and selection). | ||
#### Selection | ||
|
||
To add row selection to the table, first set up a `SelectionModel` from `@angular/cdk/collections` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment here about specificity- I want to keep it clear that users can do selection however they want. If we present it as "this is the way you are supposed to do selection", it begs the question as to why it's not just built in. I would really rather include this in an example with explanation that say "Here is the One True Way to do selection" (same for filtering) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Flexibility is nice, but most developers are just going to want a working example they can start with. |
||
that will maintain the selection state. | ||
|
||
```js | ||
const initialSelection = []; | ||
const allowMultiSelect = true; | ||
this.selection = new SelectionModel<MyDataType>(allowMultiSelect, initialSelection); | ||
``` | ||
|
||
Add a column definition for displaying the row checkboxes, including a master toggle checkbox for | ||
the header. The column name should be added to the list of displayed columns provided to the | ||
`<mat-header-row>` and `<mat-row>`. | ||
|
||
```html | ||
<ng-container matColumnDef="select"> | ||
<mat-header-cell *matHeaderCellDef> | ||
<mat-checkbox (change)="$event ? masterToggle() : null" | ||
[checked]="selection.hasValue() && isAllSelected()" | ||
[indeterminate]="selection.hasValue() && !isAllSelected()"> | ||
</mat-checkbox> | ||
</mat-header-cell> | ||
<mat-cell *matCellDef="let row"> | ||
<mat-checkbox (click)="$event.stopPropagation()" | ||
(change)="$event ? selection.toggle(row) : null" | ||
[checked]="selection.isSelected(row)"> | ||
</mat-checkbox> | ||
</mat-cell> | ||
</ng-container> | ||
``` | ||
|
||
Implement the behavior in your component's logic to handle the header's master toggle and checking | ||
if all rows are selected. | ||
|
||
```js | ||
/** Whether the number of selected elements matches the total number of rows. */ | ||
isAllSelected() { | ||
const numSelected = this.selection.selected.length; | ||
const numRows = this.dataSource.data.length; | ||
return numSelected == numRows; | ||
} | ||
|
||
/** Selects all rows if they are not all selected; otherwise clear selection. */ | ||
masterToggle() { | ||
this.isAllSelected() ? | ||
this.selection.clear() : | ||
this.dataSource.data.forEach(row => this.selection.select(row)); | ||
} | ||
``` | ||
|
||
Finally, adjust the styling for the select column so that its overflow is not hidden. This allows | ||
the ripple effect to extend beyond the cell. | ||
|
||
```css | ||
.mat-column-select { | ||
overflow: initial; | ||
} | ||
``` | ||
|
||
<!--- example(table-selection) --> | ||
|
||
### Accessibility | ||
Tables without text or labels should be given a meaningful label via `aria-label` or | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rephrase this paragraph a bit