The table component can be a static or an interactive element. Some tables provide the possiblity to add, remove, edit a row or expand it for further information.
<dt-table [dataSource]="dataSource" dtSort #sortable>
<dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
<dt-simple-number-column
name="cpu"
label="CPU"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryPerc"
label="Memory"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryConsumption"
label="Memory combined"
[displayAccessor]="combineMemory"
[sortAccessor]="memorySortAccessor"
></dt-simple-number-column>
<dt-simple-number-column
name="traffic"
label="Traffic"
[formatter]="trafficFormatter"
sortable="false"
></dt-simple-number-column>
<dt-header-row
*dtHeaderRowDef="[
'host',
'cpu',
'memoryPerc',
'memoryConsumption',
'traffic'
]"
></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
"
></dt-row>
</dt-table>
The DtTable
implementation enhances the
Material's CDK table and also
removes unneeded properties from the public API. The CDK table has a very
different approach on how to define the table template, it does not use the
native HTML table. Therefore, there are no td
, tr
or th
tags involved.
Instead, you need to define all possible columns that the table may show
(depending on the data available) and then define which subset of columns you
want to show in the table header and body by selecting from the column
definitions.
Imports
You have to import the DtTableModule
to use the dt-table
. If you want to use
the dt-expandable-cell
component, Angular's BrowserAnimationsModule
is
required for animations. For more details on this see
Step 2: Animations in the getting started guide.
If you want to use the dt-order-cell
, Angular's DragDropModule
is required
for reordering table rows via drag and drop. For more details on this see
the Order section.
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DtTableModule } from '@dynatrace/barista-components/table';
@NgModule({
imports: [BrowserAnimationsModule, DtTableModule],
})
class MyModule {}
Table inputs
The DtTable
component supports the following inputs. Find details about the
usage of each input below.
Name | Type | Default | Description |
---|---|---|---|
dataSource |
object[] | Observable | DataSource |
Data to be shown in the table. | |
loading |
boolean |
false |
Whether the table is loading or not. |
multiExpand |
boolean |
false |
Whether the table allows multiple rows to be expanded at a time. |
exportButton |
boolean |
false |
Whether the table includes an export button. |
Simple columns for basic use cases
For the most common column types (text and number columns) the Angular
components provide a DtSimpleColumn
implementation that wraps the underlying,
more complex table setup. The dtSimpleColumn
is an abstraction layer to the
full fledged table implementation to make usage of recurring-patterns easier and
to reduce boiler plate code that needs to be written to generate a simple table.
A dtTable
using a dtSimpleColumn
always needs the dtSort
directive.
<dt-table [dataSource]="dataSource" dtSort #sortable>
<dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
<dt-simple-number-column
name="cpu"
label="CPU"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryPerc"
label="Memory"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryConsumption"
label="Memory combined"
[displayAccessor]="combineMemory"
[sortAccessor]="memorySortAccessor"
></dt-simple-number-column>
<dt-simple-number-column
name="traffic"
label="Traffic"
[formatter]="trafficFormatter"
sortable="false"
></dt-simple-number-column>
<dt-header-row
*dtHeaderRowDef="[
'host',
'cpu',
'memoryPerc',
'memoryConsumption',
'traffic'
]"
></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
"
></dt-row>
</dt-table>
DtSimpleColumn
The dtSimpleColumn
provides a couple of inputs, which give the user easy
access to certain functionality of the dtTable
like sorting, formatting, and
problem indicators.
Inputs
Name | Type | Default | Description |
---|---|---|---|
name |
string |
- | The name of the dtSimpleColumn refers to the name of the column which it uses to register itself at the table. This name can be used to reference the column in the dt-row . The name input is the only required input on the simple column. |
label |
string |
- | The label defines the string rendered into the header-cell of the given column. If no label is given, the name of the cell is being used. (Optional) |
sortable |
boolean |
true |
The sortable input defines whether the column should be sortable. |
displayAccessor<T> |
(data: T, name: string) => any |
- | The displayAccessor function can be used to extract the displayable data from any row data. The name property passes the currently rendered column name, which can be used for more generic functions. If no displayAccessor is given, the dtSimpleColumn tries to extract a displayable data from rowData[name] . (Optional) |
sortAccessor<T> |
(data: T, name: string) => string | number |
- | The sortAccessor function can be used to extract sortable data from any row data. The name property passes the currently rendered column name, which can be used for more generic functions. This sortAccessor function will be used by the dataSource to access sortable values from the row data. (Optional) |
formatter |
(displayValue: any) => string | DtFormattedValue |
- | The formatter function can be used to fomat the displayed value, with either prepared DtFormatter functions or custom functions. Can be used on top of the displayAccessor function or standalone. The function gets passed either the output from the displayAccessor or the fallback data. (Optional) |
hasProblem<T> |
(data: T, name: string) => DtIndicatorThemePalette |
- | The hasProblem function can be used to evaluate if a cell should add the dtIndicator and if it should display error or warning . The function gets passed the row data and the name of the current column, which allows for more generic functions. The function needs to return either error or warning if a problem should be active. (Optional) |
dtColumnProportion |
number |
- | Exposes the dtColumnProportion of the dtCell directive for use with simple columns |
comparator<T> |
(left: T, right: T, name: string) => number |
- | The comparator function can be used to specify a custom comparator which is used to compare two rows. If this property is set, the sortAccessor for this column is ignored. This function must return < 0 if left is logically smaller than right, 0 if they are equivalent, otherwise > 0 . (Optional) |
Variants
Currently there are three predefined versions of the dtSimpleColumn
exposed:
dt-simple-number-column
, dt-simple-text-column
and dt-favorite-column
.
There are only small differences between the number and text column:
dt-simple-text-column
- When sorting this column, the sort direction will start ascending, e.g. A -> Z
- Column alignment is set to
text
-> left
dt-simple-number-column
- When sorting this column, the sort direction will start descending, e.g. 100 -> 0
- Column alignment is set to
number
-> right - When no formatter is given, the
dtCount
formatter will automatically be applied, e.g. 1000 -> 1k
dt-favorite-column
- Column alignment is set to
icon
-> center - When sorting this column, the sort direction will start descending, e.g. ★ -> ☆
Default example of a favorite column:
<dt-table [dataSource]="dataSource" dtSort #sortable>
<dt-favorite-column
name="favorite"
label="Favorite"
(favoriteToggled)="toggleFavorite($event)"
></dt-favorite-column>
<dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef dt-sort-header>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.memoryPerc }} / {{ row.memoryTotal }}
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['favorite', 'host', 'memory']"
></dt-header-row>
<dt-row *dtRowDef="let row; columns: ['favorite', 'host', 'memory']"></dt-row>
</dt-table>
When no label is given, nothing will be rendered inside the header-cell:
<dt-table [dataSource]="dataSource">
<dt-favorite-column
name="favorite"
sortable="false"
(favoriteToggled)="toggleFavorite($event)"
></dt-favorite-column>
<dt-simple-text-column
name="host"
label="Host"
sortable="false"
></dt-simple-text-column>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.memoryPerc }} / {{ row.memoryTotal }}
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['favorite', 'host', 'memory']"
></dt-header-row>
<dt-row *dtRowDef="let row; columns: ['favorite', 'host', 'memory']"></dt-row>
</dt-table>
Custom columns for advanced use cases
If the simple column implementation does not cover your use cases, you can use the underlying API to create your own column, cell, and header definitions as follows:
Each column definition is created with dt-header-cell
and dt-cell
inside an
ng-container
structural directive with a dtColumDef
attribute directive
applied to it.
<ng-container dtColumnDef="username">
<dt-header-cell *dtHeaderCellDef>User name</dt-header-cell>
<dt-cell *dtCellDef="let row"><span ngNonBindable>{{row.a}}</span></dt-cell>
</ng-container>
Note: dtCellDef
not only exports the row data but also the same properties as
*ngFor
- using the same
micro-syntax.
The table header is defined with a dt-header-row
component and a
dtHeaderRowDef
directive:
<dt-header-row *dtHeaderRowDef="['username', 'age', 'title']"></dt-header-row>
Finally the table row is defined with a dt-row
component and a dtRowDef
directive:
<dt-row *dtRowDef="let row; columns: ['username', 'age', 'title']"></dt-row>
Note: The dtRowDef
also exports row context, which can be used for event and
property bindings on the row element. See the source code of the examples on
this page to see all the pieces in place.
<dt-table [dataSource]="data">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">
<dt-info-group>
<dt-info-group-icon>
<dt-icon name="host"></dt-icon>
</dt-info-group-icon>
<dt-info-group-title>{{ row.host }}</dt-info-group-title>
Uptime: {{ row.uptime }}
</dt-info-group>
</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu | dtPercent }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ combineMemory(row) }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.traffic | dtMegabytes: 1024 | dtRate: 's' }}
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
Components and attributes that define a table
Name | Type | Description |
---|---|---|
dtColumnDef |
Attribute | Name for the column (to be used in the header and row definitions). |
dtColumnAlign |
Attribute | Sets the column alignment. Find possible values below in the "Alignment in tables" section. |
dt-header-cell |
Directive | Adds the appropriate classes (the generic dt-header-cell and the cell specific dt-column-css_friendly_column_name) and role (so the browser knows how to parse it. In this case it makes it act as a column header in a native html table) |
*dtHeaderCellDef |
Attribute | Captures the template of a column's header cell (the title for the column in the header) as well as cell-specific properties so the table can render it's header properly. |
dt-cell |
Component | Adds the appropriate classes and role (so the browser knows how to parse it. In this case it makes it act as a grid cell in a native html table). |
*dtCellDef |
Attribute | Exports the row data and the same properties as an ngFor in a way you can define what the cell should show. It also captures the template of the column's data row cell. |
dt-header-row |
Component | Placeholder for the header row. It is a container that contains the cell outlet. Adds the appropriate class and role. |
*dtHeaderRowDef |
Attribute | Defines the visible columns in the header out of all defined ones by receiving a columnName[]. |
dt-row |
Component | Placeholder for the data rows. It is a container for the cell outlet. Adds the right class and role. |
*dtRowDef |
Attribute | Defines the visible columns in each row by receiving a columnName[] and also exposes the same micro-syntax that the dt-cell but for event and property binding. |
Alignment in tables
Content can be centered, left- or right-aligned depending on the data. Header text should always follow the same alignment as the column content.
- Left-aligned content
- Text
- Identification numbers beginning with letters, e.g. ID
- Right-aligned content
- Numbers
- Date, time, year,...
- IP addresses
- Center-aligned content
- Icons
- Interactive components (e.g. switches)
Add the dtColumnAlign
attribute to the ng-container
that wraps the column
definition to define the column's text alignment. The attribute accepts the
following values:
Attribute values | Alignment |
---|---|
left |
left |
text |
left |
id |
left |
right |
right |
number |
right |
date |
right |
ip |
right |
center |
center |
icon |
center |
control |
center |
Data source
The data source contains the data to be shown in the table. It can be an array,
an observable holding an array or a DataSource
object.
The Angular components provide a DtTableDataSource
that provides a lot of
functionality (like filtering, sorting, pagination) already set up. The
DtTableOrderDataSource
provides functionality to reorder the table, but does
not work in combination with filtering, sorting or pagination. For use cases
that can not be implemented using the DtTableDataSource
you can always create
your own data source that implements the DataSource
interface.
Sorting
The DtSort
and dt-sort-header
are used to add sorting functionality to the
table. To add sorting capabilities to a table add the dtSort
directive to the
dt-table
component.
<dt-table ... dtSort ...></dt-table>
For each column that should be sortable by the user add dt-sort-header
to the
dt-header-cell
. The dt-sort-header
registers itself with the ID given to the
dtColumnDef
with the DtSort
directive.
<dt-header-cell dt-sort-header ...></dt-header-cell>
<dt-table
[dataSource]="dataSource"
dtSort
(dtSortChange)="sortData($event)"
[dtSortDisabled]="disableSorting"
[dtSortActive]="'cpu'"
dtSortStart="asc"
dtSortDirection="desc"
>
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell
*dtHeaderCellDef
dt-sort-header
sort-aria-label="Change sort order for hosts"
>
Host
</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell
*dtHeaderCellDef
dt-sort-header
start="desc"
sort-aria-label="Change sort order for CPUs"
>
CPU
</dt-header-cell>
<dt-cell *dtCellDef="let row"> {{ row.cpu | dtPercent }} </dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell
*dtHeaderCellDef
dt-sort-header
start="desc"
sort-aria-label="Change sort order for memory"
>
Memory
</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.memoryPerc | dtPercent }} of {{ row.memoryTotal | dtBytes }}
</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell
*dtHeaderCellDef
disabled
dt-sort-header
sort-aria-label="Change sort order for network traffic"
>
Network traffic
</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.traffic | dtBytes | dtRate: 's' }}
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="disableSorting = !disableSorting"
>
Toggle disable sorting for all columns
</button>
DtSort
You can set the following inputs and outputs on the dtSort
directive.
Inputs
Name | Type | Default | Description |
---|---|---|---|
dtSortActive |
string |
The ID of the most recent active column. | |
dtSortDirection |
DtSortDirection |
asc |
The sort direction of the currently active colum, which can be used for initially sorting it. |
dtSortDisabled |
boolean |
false |
Whether sorting is disabled for the entire table. |
dtSortStart |
DtSortDirection |
Sort direction in which a column is initially sorted when the user interacts with it. May be overriden by the DtSortHeader's sort start. |
Outputs
Name | Type | Default | Description |
---|---|---|---|
sortChange |
EventEmitter<DtSortEvent> |
Event emmited when the user changes either the active sort or the sorting direction. |
Methods
Name | Description | Parameters | Return value |
---|---|---|---|
sort |
Sets the active sort ID and new sort direction | sortable: DtSortHeader or active: string, direction : DtSortDirection |
void |
DtSortHeader
You can set the following inputs and outputs on the dt-sort-header
component.
Inputs
Name | Type | Default | Description |
---|---|---|---|
disabled |
boolean |
Whether sorting is disabled for this sort header. | |
start |
DtSortDirection |
asc |
Overrides the sort start value of the containing DtSort . |
sort-aria-label |
string |
Sets the aria label for the button used for sorting. |
Accessibility
Please provide a sort-aria-label
for each dt-sort-header
to make the sorting
experience accessible for all users. E.g. Change sort order for column hosts
.
DtSortDirection
The type used for the sort direction, either asc
or desc
.
DtSortEvent
The event emitted when the user changes either the active sort or the sorting direction. The event contains the following properties.
Name | Type | Description |
---|---|---|
active |
string |
The ID of the currently active column. |
direction |
DtSortDirection |
The direction for the currently active column. |
Ordering
The DtOrder
and dt-order-cell
in combination with Angular's DragDropModule
are used to add ordering functionality to the table. To add ordering
capabilities to a table, import the DragDropModule
and add the dtOrder
and
cdkDropList
directive and cdkDropListData
input to the dt-table
component.
When using the dt-order-cell
, the data source provided for the table must be
of type DtTableOrderDataSource
. Tables using the dt-order-column
can't be
sorted or paginated.
<dt-table ... dtOrder cdkDropList [cdkDropListData]="dataSource" ...></dt-table>
The cdkDropListData
gets the same data as the table's dataSource
input. When
combining the dt-order-cell
with dt-simple-column
s, their sortable
input
should be set to false. The DtTableOrderDataSource
does not mutate the
original data when ordering, if you want to persist the ordered state you have
to take care of that yourself.
<dt-table
[dataSource]="dataSource"
dtOrder
[dtOrderDisabled]="disableOrdering"
cdkDropList
[cdkDropListData]="dataSource"
>
<ng-container dtColumnDef="order" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
<dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
</dt-order-cell>
</ng-container>
<dt-simple-text-column
name="name"
label="Rule name"
sortable="false"
></dt-simple-text-column>
<dt-header-row *dtHeaderRowDef="['order', 'name']"></dt-header-row>
<dt-row *dtRowDef="let row; columns: ['order', 'name']"></dt-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="disableOrdering = !disableOrdering"
>
Toggle disable ordering
</button>
DtOrder
You can set the following inputs and outputs on the dtOrder
directive.
Inputs
Name | Type | Default | Description |
---|---|---|---|
dtOrderDisabled |
boolean |
false |
Whether ordering is disabled for the entire table. |
Outputs
Name | Type | Default | Description |
---|---|---|---|
dtOrderChange |
EventEmitter<DtOrderChangeEvent> |
Event emmited when the user changes the order of the table, either by dragging a row to a new position or by changing the input value. |
Methods
Name | Description | Parameters | Return value |
---|---|---|---|
order |
Changes the position of a row based on the row's index | currentIndex: number targetIndex: number |
Ordering with expandable rows
Ordering also works with custom columns and expandable rows.
<dt-table
[dataSource]="dataSource"
[multiExpand]="multiExpand"
dtOrder
cdkDropList
[cdkDropListData]="dataSource"
>
<ng-container [dtColumnDef]="'order'" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
<dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
</dt-order-cell>
</ng-container>
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="details" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
<dt-expandable-cell
*dtCellDef
ariaLabel="Expand the row"
></dt-expandable-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['order', 'details', 'host', 'memory', 'cpu', 'traffic']"
></dt-header-row>
<dt-expandable-row
*dtRowDef="
let row;
columns: ['order', 'details', 'host', 'memory', 'cpu', 'traffic']
"
[expanded]="row.expanded"
>
<ng-template dtExpandableRowContent>
Expandable section for {{ row.host }}
</ng-template>
</dt-expandable-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="multiExpand = !multiExpand"
>
Toggle multiexpand (current value: {{ multiExpand }})
</button>
Ordering with data from observable
<button
*ngIf="!isSubscribed; else cancel"
class="dt-example-button"
dt-button
(click)="startSubscription()"
>
Start subscription
</button>
<button
class="dt-example-button"
dt-button
variant="secondary"
(click)="clearRows()"
>
Clear
</button>
<dt-table
[dataSource]="dataSource"
dtOrder
cdkDropList
[cdkDropListData]="dataSource"
>
<ng-container [dtColumnDef]="'order'" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
<dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
</dt-order-cell>
</ng-container>
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="control">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['order', 'host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['order', 'host', 'cpu', 'memory', 'traffic']"
></dt-row>
<dt-empty-state role="row">
<dt-empty-state-item role="cell">
<dt-empty-state-item-img>
<img
alt="glass"
src="data:image/png;base64,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"
/>
</dt-empty-state-item-img>
<dt-empty-state-item-title aria-level="1">
No data that matches your query
</dt-empty-state-item-title>
To add data to the query, click the start subscription button.
</dt-empty-state-item>
</dt-empty-state>
</dt-table>
<ng-template #cancel>
<button class="example-button" dt-button (click)="cancelSubscription()">
Cancel subscription
</button>
</ng-template>
DtOrderEvent
The event emitted when the user changes the order of the table, either by dragging a row to a new position or by changing the input value. The event contains the following properties.
Name | Type | Description |
---|---|---|
previousIndex |
number |
The index of the row prior to changing the order. |
currentIndex |
number |
The index of the row after changing the order. |
Searching/Filtering
When tables contain large amounts of data, make it easier for the user to find
entries by providing a search field above the table. The DtTableSearch
component can be used in combination with a table to provide this functionality.
Filtering data for the table means filtering out rows that are passed via the
data source. For highlighting the matched strings in the table the DtHighlight
component can be used.
<dt-table-search
name="tableSearch"
[(ngModel)]="searchValue"
placeholder="Search table data..."
aria-label="Search table data"
></dt-table-search>
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">
<dt-highlight [term]="searchValue">{{ row.host }}</dt-highlight>
</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ combineMemory(row) }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.traffic | dtMegabytes: 1024 | dtRate: 's' }}
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
DtTableSearch
Inputs
Name | Type | Default | Description |
---|---|---|---|
value |
string |
'' |
The current search term. |
placeholder |
string |
undefined |
Placeholder string for the input field (always needs to start with "Search ..."). |
aria-label |
string |
undefined |
An ARIA label describing the input field. |
aria-labelledby |
string |
undefined |
A reference to an ARIA description of the input field. |
Outputs
Name | Type | Description |
---|---|---|
valueChange |
EventEmitter<DtTableSearchChangeEvent> |
Event emitted when the user changes the search term. |
Pagination and show more
The DtPagination
component can be used in combination with a table to provide
pagination for large datasets.
<dt-table [dataSource]="dataSource" dtSort #sortable>
<dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
<dt-simple-number-column name="cpu" label="CPU"></dt-simple-number-column>
<dt-simple-number-column
name="memoryPerc"
label="Memory"
[formatter]="percentageFormatter"
dtColumnProportion="3"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryConsumption"
label="Memory combined"
[displayAccessor]="combineMemory"
[sortAccessor]="memorySortAccessor"
></dt-simple-number-column>
<dt-simple-number-column
name="traffic"
label="Traffic"
sortable="false"
[formatter]="trafficFormatter"
></dt-simple-number-column>
<dt-header-row
*dtHeaderRowDef="[
'host',
'cpu',
'memoryPerc',
'memoryConsumption',
'traffic'
]"
></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
"
></dt-row>
</dt-table>
<dt-pagination></dt-pagination>
In some use cases we might not know how much data we have in total. In this case
a DtShowMore
componenent might be more suitable.
<dt-table [dataSource]="dataSource">
<dt-simple-text-column
name="host"
label="Host"
sortable="false"
></dt-simple-text-column>
<dt-simple-number-column
name="cpu"
label="CPU"
sortable="false"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="memory"
label="Memory"
sortable="false"
[formatter]="percentageFormatter"
></dt-simple-number-column>
<dt-simple-number-column
name="traffic"
label="Traffic"
sortable="false"
[formatter]="trafficFormatter"
></dt-simple-number-column>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
<button dt-show-more (click)="loadMore()">Show 5 more</button>
Selectable table rows
The DtTableRowSelector
can be used for selectable rows in a table and the
DtTableHeaderSelector
to provide bulk selection in the column header.
The DtTableSelection
directive has to be added to the table to enable
selection handling. The directive also provides access to the currently selected
rows and allows you to change selection programmatically. It also supports a
selection limit by providing a DtTableSelectionConfig
via the
DT_TABLE_SELECTION_CONFIG
injection token.
Inputs
Name | Type | Default | Description |
---|---|---|---|
dtTableSelectionInitial |
T[] |
[] |
The rows that should be selected initially. |
dtTableIsRowDisabled |
Predicate<T> |
() => false |
Predicate to disable matching rows |
Outputs
Name | Type | Description |
---|---|---|
dtTableSelectionChange |
Observable<SelectionChange<T>> |
Event emitted when the selection changes either by user interaction or programmatically. |
<dt-table
[dataSource]="dataSource"
dtSort
dtTableSelection
[dtTableIsRowDisabled]="isDisabled"
>
<ng-container dtColumnDef="checkbox">
<dt-table-header-selector
*dtHeaderCellDef
aria-label="Toggle all hosts"
></dt-table-header-selector>
<dt-table-row-selector
*dtCellDef="let row"
[row]="row"
[aria-label]="'Toggle ' + row.host"
></dt-table-row-selector>
</ng-container>
<dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
<dt-simple-number-column name="cpu" label="CPU"></dt-simple-number-column>
<dt-header-row *dtHeaderRowDef="['checkbox', 'host', 'cpu']"></dt-header-row>
<dt-row *dtRowDef="let row; columns: ['checkbox', 'host', 'cpu']"></dt-row>
</dt-table>
Current selection: {{ getCurrentSelection() }}
Sorting, paging and filtering out of the box with DtTableDataSource
Merging the streams for sorting, filtering and pagination can get quite tricky.
The DtTableDataSource
has all this features already set up.
Unified sorting (locale-aware for strings, null/undefined value treatment) is
possible when using the DtTableDataSource. To do this, create a new
DtTableDataSource
instance with the data. You will have to connect the input
instances for dtSort
to the DtTableDataSource
.
@Component({
template: `
<input dtInput (input)="updateFilter($event)" />
<dt-table [dataSource]="dataSource" dtSort #sortable>
[... column and row definitions]
</dt-table>
<dt-pagination></dt-pagination>
`,
})
export class TableComponent implements OnInit {
// Get the viewChild to pass the sorter, pagination, and filter reference to the datasource.
@ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort;
@ViewChild(DtPagination, { static: true }) pagination: DtPagination;
// Create the Datasource instanciate it.
dataSource: DtTableDataSource<object>;
constructor() {
this.dataSource = new DtTableDataSource(this.data);
}
ngOnInit(): void {
// Set the dtSort reference on the dataSource, so it can react to sorting.
this.dataSource.sort = this.sortable;
// Set the dtPagination reference on the dataSource, so it can page the data.
this.dataSource.pagination = this.pagination;
// Set the pageSize to override the default page size.
this.dataSource.pageSize = 10;
}
updateFilter(event: InputEvent): void {
this.dataSource.filter = event.srcElement.value;
}
}
The DtTableDataSource
exposes two functions, that let the user define sort
accessors for named columns. This enables the user to leverage
DtTableDataSource
sorting without the use of dt-simple-columns
. The function
addSortAccessorFunction(columnName: string, fn: DtSortAccessorFunction)
can be
used to add a custom sortAccessor function to the data source. The custom added
sort accessors takes precedence over the automatically added ones from
dt-simple-columns
.
The function removeSortAccessorFunction(columnName: string)
enables the user
to remove a previously defined sortAccessor function.
export class TableComponent implements OnInit, OnDestroy {
//...
// Create the Datasource instanciate it.
dataSource: DtTableDataSource<object>;
constructor() {
this.dataSource = new DtTableDataSource(this.data);
this.dataSource.addSortAccessorFunction('memory', (row) => {
return (row.memoryPerc / 100) * row.memoryTotal;
});
}
ngOnDestroy() {
// Not necessary, but possible
this.dataSource.removeSortAccessorFunction('memory');
}
}
The DtTableDataSource
also exposes two functions, that let the user define
custom comparators for named columns. This enables the user to leverage
DtTableDataSource
comparing without the use of dt-simple-columns
. The
function
addComparatorFunction(columnName: string, fn: DtColumnComparatorFunction)
can
be used to add a custom comparator function to the data source. The custom added
comparator takes precedence over defined sortAccessor functions.
The function removeComparatorFunction(columnName: string)
enables the user to
remove a previously defined comparator function.
<dt-table [dataSource]="dataSource" dtSort #sortable>
<dt-simple-text-column
name="host"
label="Host"
[comparator]="compareStringLengths"
></dt-simple-text-column>
<dt-simple-text-column
name="namespace"
label="Namespace"
></dt-simple-text-column>
<dt-header-row *dtHeaderRowDef="['host', 'namespace']"></dt-header-row>
<dt-row *dtRowDef="let row; columns: ['host', 'namespace']"></dt-row>
</dt-table>
Expandable table rows
To show more details in context of a single table row, use expandable rows. They
can be defined using the dt-expandable-row
component. An expandable row has
to contain a column with a details cell. A details cell can be added using
dt-expandable-cell
. The content inside the dt-expandable-row
needs to be
wrapped inside a ng-template
with the dtExpandableRowContent
directive to
lazy load the content when the row is expanded.
<dt-table [dataSource]="dataSource" [multiExpand]="multiExpand">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="control">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="details">
<dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
<dt-expandable-cell
*dtCellDef
ariaLabel="Expand the row"
></dt-expandable-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['details', 'host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-expandable-row
*dtRowDef="
let row;
columns: ['details', 'host', 'cpu', 'memory', 'traffic']
"
[expanded]="row.expanded"
>
<ng-template dtExpandableRowContent>
Expandable section for {{ row.host }}
</ng-template>
</dt-expandable-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="multiExpand = !multiExpand"
>
Toggle multiexpand (current value: {{ multiExpand }})
</button>
Component/Attribute | Type | Description |
---|---|---|
dt-expandable-row |
Component | Placeholder for the expandable data rows. It is a container for the cell outlet and an expandable section. Adds the right class and role. |
dt-expandable-cell |
Component | Adds the appropriate classes, role and content for the details cell in an expandable table. |
ng-template dtExpandableContent |
Directive | Wraps the content of the expandable row for lazy loading |
Use the table's multiExpand
input to allow multiple rows to be expanded at a
time. The expanded state of an expandable row can be set programmatically by
using the row's expanded
input.
DtExpandableRow
Inputs
Name | Type | Default | Description |
---|---|---|---|
expanded |
boolean |
false |
Whether the row is expanded or not. |
Outputs
Name | Type | Description |
---|---|---|
expandChange |
EventEmitter<DtExpandableRowChangeEvent> |
Event emitted when the row's expandable state changes. |
expanded |
EventEmitter<DtExpandableRow> |
Event emitted when the row is expanded. |
collapsed |
EventEmitter<DtExpandableRow> |
Event emitted when the row is collapsed. |
DtExpandableCell
Expandable rows have to contain one column definition which contains a
dt-expandable-cell
. Its aria-label
or aria-labelledby
input describes the
action of toggling the state of the expandable row. A sample column definition
for the details column could look like this:
<ng-container dtColumnDef="details" dtColumnAlign="control">
<dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
<dt-expandable-cell
*dtCellDef
ariaLabel="Expand the row"
></dt-expandable-cell>
</ng-container>
States
Empty state
When there is no data to display an empty state is shown. It can consist of some
text that explains why there is no content and an illustration that helps to
visualize the problem. Pass an empty state to the table using the
<dt-empty-state>
component or a
custom empty state.
<dt-table [dataSource]="dataSource" dtSort [dtSortDisabled]="true">
<dt-simple-text-column
name="usersId"
label="Users ID"
></dt-simple-text-column>
<dt-simple-number-column
name="sessionCount"
label="Session count"
></dt-simple-number-column>
<dt-simple-number-column
name="averageDuration"
label="Average duration"
></dt-simple-number-column>
<dt-simple-number-column
name="errors"
label="Errors"
></dt-simple-number-column>
<dt-simple-text-column name="country" label="Country"></dt-simple-text-column>
<dt-simple-text-column name="city" label="City"></dt-simple-text-column>
<dt-simple-text-column
name="browserFamily"
label="Browser family"
></dt-simple-text-column>
<dt-simple-text-column name="device" label="Device"></dt-simple-text-column>
<dt-empty-state role="row">
<dt-empty-state-item role="cell">
<dt-empty-state-item-img>
<img
alt="glass"
src="data:image/png;base64,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"
/>
</dt-empty-state-item-img>
<!-- Give the empty state item an aria-level to indicate which level of heading it represents within the page -->
<dt-empty-state-item-title aria-level="1">
{{ emptyState.title }}
</dt-empty-state-item-title>
{{ emptyState.message }}
</dt-empty-state-item>
</dt-empty-state>
<dt-header-row
*dtHeaderRowDef="[
'usersId',
'sessionCount',
'averageDuration',
'errors',
'country',
'city',
'browserFamily',
'device'
]"
></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: [
'usersId',
'sessionCount',
'averageDuration',
'errors',
'country',
'city',
'browserFamily',
'device'
]
"
></dt-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="toggleEmptyState()"
>
Toggle empty state
</button>
Loading state
You can mark the table as loading using the table's loading
input and pass the
content to display with dtTableLoadingState
directive.
<dt-table [dataSource]="dataSource" [loading]="tableLoading">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-loading-distractor dtTableLoadingState>
Loading...
</dt-loading-distractor>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="tableLoading = !tableLoading"
>
Toggle loading property
</button>
Problems: errors and warnings
If a table cell contains a problematic value, an indicator is used to highlight it with the error (red) status color. Warnings in tables indicate configuration issues using the warning (yellow) status color.
To get an error or warning indicator use the dtIndicator
directive inside your
dt-cell
components on any HTML element or on your dt-cell
component
directly. The dt-row
and dt-expandable-row
will pick up if any dtIndicator
was used inside the row's dt-cell
and show the correct indicator. If one
indicator has an error
state set, the indicator on the row is an error
indicator (i.e. error trumps warning). You can control the active state of the
indicator by using the input named the same as dtIndicator
.
<dt-cell [dtIndicator]="active" ...></dt-cell>
Single metric problem indication
If a single metric in a table entry is affected, only the affected value is highlighted.
Problem indication of entity or table row
If the problem affects the entity, but the affected metric is not in the table, the entity name is highlighted by the appropriate status color.
Note: Don't color hyperlinks even if the whole entity is affected, in this case use only the indicator on the left.
The example below shows both usages – a single metric inside a cell and the
entire cell enhanced with the dtIndicator
.
<dt-table [dataSource]="_dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.name }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell
[dtIndicator]="metricHasProblem(row, 'cpuUsage')"
[dtIndicatorColor]="metricIndicatorColor(row, 'cpuUsage')"
*dtCellDef="let row"
>
{{ row.cpuUsage | dtPercent }}
</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">
<span
[dtIndicator]="metricHasProblem(row, 'memoryPerc')"
[dtIndicatorColor]="metricIndicatorColor(row, 'memoryPerc')"
>
{{ row.memoryPerc | dtPercent }}
</span>
of
<span
[dtIndicator]="metricHasProblem(row, 'memoryTotal')"
[dtIndicatorColor]="metricIndicatorColor(row, 'memoryTotal')"
>
{{ row.memoryTotal | dtBytes }}
</span>
</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.traffic | dtBits | dtRate: 's' }}
</dt-cell>
</ng-container>
<ng-container dtColumnDef="empty">
<dt-cell *dtCellDef="let row">This is empty</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
<button
class="dt-toggle"
dt-button
variant="secondary"
(click)="_toggleProblem()"
>
Toggle problem
</button>
Advanced usage
Sticky header
To make the table header sticky, set the sticky
input on the dtHeaderRowDef
directive.
<dt-header-row
*dtHeaderRowDef="['username', 'age', 'title']; sticky: true"
></dt-header-row>
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']; sticky: true"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
Custom column width
The column width proportion can be customized using the dtColumnProportion
attribute. It accepts a number input, e.g. [dtColumnProportion]="2"
means that
this column's width will be doubled compared to the regular ones.
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text" dtColumnProportion="3">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
The column's minimum width can be set using the dtColumnMinWidth
attribute. It
accepts a CSS string describing the minimum width for the column.
[dtColumnMinWidth]="200"
means that this column's width will be at least
200px.
<dt-table [dataSource]="dataSource">
<ng-container
dtColumnDef="host"
dtColumnAlign="text"
[dtColumnMinWidth]="300"
>
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number" dtColumnMinWidth="50%">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
Dynamic columns
You can bind the column definitions to an array with a *ngFor
directive.
<dt-table [dataSource]="dataSource">
<ng-container
*ngFor="let column of columnsDef"
[dtColumnDef]="column.id"
[dtColumnAlign]="column.type"
>
<dt-header-cell *dtHeaderCellDef>{{ column.title }}</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row[column.id] }}</dt-cell>
</ng-container>
<dt-header-row *dtHeaderRowDef="columnsName"></dt-header-row>
<dt-row *dtRowDef="let row; columns: columnsName"></dt-row>
</dt-table>
Interactive rows
To apply a hover effect for the table rows add interactiveRows
on the
dt-table
component.
<dt-table [dataSource]="dataSource" interactiveRows>
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
</dt-table>
Tables with two lines per row
If you want to have 2 lines of text and maybe an icon inside a row you can use
the <dt-info-group>
component. You can also take a look at the
<dt-info-group>
component's page for further information.
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="service">
<dt-header-cell *dtHeaderCellDef>Service</dt-header-cell>
<dt-cell *dtCellDef="let row">
<dt-info-group>
<dt-info-group-icon>
<dt-icon name="services"></dt-icon>
</dt-info-group-icon>
<dt-info-group-title>{{ row.service }}</dt-info-group-title>
{{ row.location }}
</dt-info-group>
</dt-cell>
</ng-container>
<ng-container dtColumnDef="responseTime" dtColumnAlign="right">
<dt-header-cell *dtHeaderCellDef>Response time</dt-header-cell>
<dt-cell *dtCellDef="let row">
{{ row.responseTime | dtCount }} ms
</dt-cell>
</ng-container>
<ng-container dtColumnDef="failureRate" dtColumnAlign="right">
<dt-header-cell *dtHeaderCellDef>Failure rate</dt-header-cell>
<dt-cell *dtCellDef="let row"> {{ row.failureRate | dtPercent }} </dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['service', 'responseTime', 'failureRate']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['service', 'responseTime', 'failureRate']"
></dt-row>
</dt-table>
Responsive table
Since some tables might have a lot of data in them and screen space is very limited especially on devices with smaller screens you might want to switch between a table with expandable rows and normal rows. The example below shows a very simple approach how this might be done.
<dt-container-breakpoint-observer>
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="control">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="details" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
<dt-expandable-cell *dtCellDef></dt-expandable-cell>
</ng-container>
<dt-header-row *dtHeaderRowDef="_headerColumns"></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: ['host', 'cpu', 'memory', 'traffic'];
let rowIndex = index;
when: !_isTableNarrow
"
></dt-row>
<dt-expandable-row
*dtRowDef="
let row;
columns: ['details', 'host', 'cpu'];
let rowIndex = index;
when: _isTableNarrow
"
>
<ng-template dtExpandableRowContent>
<dt-key-value-list>
<dt-key-value-list-item>
<dt-key-value-list-key>Memory</dt-key-value-list-key>
<dt-key-value-list-value>{{ row.memory }}</dt-key-value-list-value>
</dt-key-value-list-item>
<dt-key-value-list-item>
<dt-key-value-list-key>Traffic</dt-key-value-list-key>
<dt-key-value-list-value>{{ row.traffic }}</dt-key-value-list-value>
</dt-key-value-list-item>
</dt-key-value-list>
</ng-template>
</dt-expandable-row>
</dt-table>
</dt-container-breakpoint-observer>
Observable as data source
You can pass an observable to the [dataSource] property.
<button
*ngIf="!isSubscribed; else cancel"
class="dt-example-button"
dt-button
(click)="startSubscription()"
>
Start subscription
</button>
<button
class="dt-example-button"
dt-button
variant="secondary"
(click)="clearRows()"
>
Clear
</button>
<dt-table [dataSource]="dataSource">
<ng-container dtColumnDef="host" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="cpu" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="memory" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
</ng-container>
<ng-container dtColumnDef="traffic" dtColumnAlign="control">
<dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
<dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
></dt-header-row>
<dt-row
*dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
></dt-row>
<dt-empty-state role="row">
<dt-empty-state-item role="cell">
<dt-empty-state-item-img>
<img
alt="glass"
src="data:image/png;base64,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"
/>
</dt-empty-state-item-img>
<dt-empty-state-item-title aria-level="1">
No data that matches your query
</dt-empty-state-item-title>
To add data to the query, click the start subscription button.
</dt-empty-state-item>
</dt-empty-state>
</dt-table>
<ng-template #cancel>
<button class="example-button" dt-button (click)="cancelSubscription()">
Cancel subscription
</button>
</ng-template>
Extending DtSimpleColumn
You can extend from the simpleColumn to create your own predefined simplecolumn.
To do this, simply extend from the DtSimpleColumnBase<T>
abstract class and
implement the deviation that suits your needs. A basic template for the
simpleColumn could look like this (example from the dt-simple-number-column
).
<ng-container [dtColumnDef]="name" dtColumnAlign="number">
<ng-container *dtHeaderCellDef>
<dt-header-cell *ngIf="!sortable">{{ label || name }}</dt-header-cell>
<dt-header-cell *ngIf="sortable" dt-sort-header start="desc">
{{ label || name }}
</dt-header-cell>
</ng-container>
<dt-cell
*dtCellDef="let data"
[dtIndicator]="_getIndicator(data, name)"
[dtIndicatorColor]="_getIndicator(data, name)"
>
{{ _getData(data) }}
</dt-cell>
</ng-container>
Exporting
Simple
By setting the showExportButton
input to true
, an dtContextDialog
button
is added just below the table, or in line with pagination if present.
Alternatively, you may set it to visible
or table
to only show those
buttons. Developers should prefer true
over the alternatives as it gives the
user the most value; however, limiting the output may be desirable if there are,
for example, many columns in the table data which should not be exported. This
dialog can contain up to 2 buttons:
- Export table data which triggers a download of the currently filtered data as shown, without regard for pagination.
- Export visible data which triggers a download of the filtered data from the datasource and does not use a displayAccessor.
To exclude certain columns from export, set exportExcludeList
to a string
array of column names to exclude.
<dt-table
[dataSource]="dataSource"
dtSort
#sortable
[showExportButton]="true"
[exportExcludeList]="['action']"
>
<ng-container dtColumnDef="host" dtColumnAlign="text" dtColumnProportion="3">
<dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
<dt-cell *dtCellDef="let row">
<dt-info-group>
<dt-info-group-icon>
<dt-icon name="host"></dt-icon>
</dt-info-group-icon>
<dt-info-group-title>{{ row.host }}</dt-info-group-title>
Uptime: {{ row.uptime }}
</dt-info-group>
</dt-cell>
</ng-container>
<ng-container
dtColumnDef="techType"
dtColumnAlign="text"
dtColumnProportion="1"
>
<dt-header-cell start="asc" *dtHeaderCellDef dt-sort-header i18n
>Technology</dt-header-cell
>
<dt-cell *dtCellDef="let row"> {{techType(row)}} </dt-cell>
</ng-container>
<dt-simple-number-column
name="cpu"
label="CPU"
dtColumnProportion="1"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryPerc"
label="Memory"
[formatter]="percentageFormatter"
dtColumnProportion="1"
></dt-simple-number-column>
<dt-simple-number-column
name="memoryConsumption"
label="Memory combined"
[displayAccessor]="combineMemory"
[sortAccessor]="memorySortAccessor"
dtColumnProportion="2"
></dt-simple-number-column>
<dt-simple-number-column
name="traffic"
label="Traffic"
sortable="false"
[formatter]="trafficFormatter"
dtColumnProportion="2"
></dt-simple-number-column>
<ng-container dtColumnDef="action" dtColumnAlign="text">
<dt-header-cell *dtHeaderCellDef>Action</dt-header-cell>
<dt-cell *dtCellDef="let row">
<a href="/filter" dt-icon-button>
<dt-icon variant="secondary" name="filter"></dt-icon>
</a>
<dt-context-dialog
aria-label="Show more details"
ariaLabelClose="Close context dialog"
>
<p>Drilldowns go here</p>
</dt-context-dialog>
</dt-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="[
'host',
'techType',
'cpu',
'memoryPerc',
'memoryConsumption',
'traffic',
'action'
]"
></dt-header-row>
<dt-row
*dtRowDef="
let row;
columns: ['host', 'techType', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic', 'action']
"
></dt-row>
</dt-table>
<dt-pagination></dt-pagination>
Selection
If dtTableSelection
is enabled and you have connected dtTableSelection
to
dtTableDataSource
(similar to dtSort
), you also will have a third button:
- Export selected rows which triggers a download of the display data, but just for selected rows.
Note: in this example showExportButton
is set to visible
to demonstrate the
suppression of the Export table data button.
<dt-table
[dataSource]="dataSource"
dtSort
dtTableSelection
showExportButton="visible"
[dtTableIsRowDisabled]="isDisabled"
exportExcludeList="'details','checkbox'"
>
<ng-container dtColumnDef="checkbox" dtColumnProportion="1">
<dt-table-header-selector
*dtHeaderCellDef
aria-label="Toggle all hosts"
></dt-table-header-selector>
<dt-table-row-selector
*dtCellDef="let row"
[row]="row"
[aria-label]="'Toggle ' + row.host"
></dt-table-row-selector>
</ng-container>
<dt-simple-text-column
name="host"
label="Host"
dtColumnProportion="2"
></dt-simple-text-column>
<dt-simple-number-column
name="cpu"
label="CPU"
dtColumnProportion="1"
></dt-simple-number-column>
<ng-container dtColumnDef="details" dtColumnAlign="number">
<dt-header-cell *dtHeaderCellDef dtColumnProportion="1"
>Details</dt-header-cell
>
<dt-expandable-cell
*dtCellDef
ariaLabel="Expand the row"
></dt-expandable-cell>
</ng-container>
<dt-header-row
*dtHeaderRowDef="['checkbox', 'details', 'host', 'cpu']"
></dt-header-row>
<dt-expandable-row
*dtRowDef="let row; columns: ['checkbox', 'details', 'host', 'cpu']"
>
<ng-template dtExpandableRowContent>
Expandable section for {{ row.host }}
</ng-template>
</dt-expandable-row>
</dt-table>
Current selection: {{ getCurrentSelection() }}