Table

A table is a two-dimensional structure composed of rows and columns displaying a set of comparable data.

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.

´ Loading interactive demo...
<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> export class TableDefaultExample implements AfterViewInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; // Initialize the table's data source dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngAfterViewInit(): void { // Set the dtSort reference on the dataSource, so it can react to sorting. this.dataSource.sort = this.sortable; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } } <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> export class TableDefaultExample implements AfterViewInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; // Initialize the table's data source dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngAfterViewInit(): void { // Set the dtSort reference on the dataSource, so it can react to sorting. this.dataSource.sort = this.sortable; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } }

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.

import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DtTableModule } from '@dynatrace/angular-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.

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.

´ Loading interactive demo...
<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> export class TableDefaultExample implements AfterViewInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; // Initialize the table's data source dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngAfterViewInit(): void { // Set the dtSort reference on the dataSource, so it can react to sorting. this.dataSource.sort = this.sortable; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } } <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> export class TableDefaultExample implements AfterViewInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; // Initialize the table's data source dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngAfterViewInit(): void { // Set the dtSort reference on the dataSource, so it can react to sorting. this.dataSource.sort = this.sortable; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } }

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

Variants

Currently there are two predefined versions of the dtSimpleColumn exposed: dt-simple-number-column and dt-simple-text-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

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.

´ Loading interactive demo...
<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> export class TableCustomColumnsExample { data: object[] = [ { host: 'et-demo-2-win4', uptime: '48 days', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 75100000, }, { host: 'et-demo-2-win3', uptime: '3 hours', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', uptime: '113 days', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', uptime: '5 days', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } } <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> export class TableCustomColumnsExample { data: object[] = [ { host: 'et-demo-2-win4', uptime: '48 days', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 75100000, }, { host: 'et-demo-2-win3', uptime: '3 hours', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', uptime: '113 days', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', uptime: '5 days', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } }

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. 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>
´ Loading interactive demo...
<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 dt-button variant="secondary" (click)="disableSorting = !disableSorting" > Toggle disable sorting for all columns </button> export class TableSortingExample { disableSorting = false; dataSource = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; sortData(event: DtSortEvent): void { const data = this.dataSource.slice(); this.dataSource = data.sort((a, b) => { const isAsc = event.direction === 'asc'; switch (event.active) { case 'host': return this.compare(a.host, b.host, isAsc); case 'cpu': return this.compare(a.cpu, b.cpu, isAsc); case 'memory': return this.compare(a.memoryPerc, b.memoryPerc, isAsc); case 'traffic': return this.compare(a.traffic, b.traffic, isAsc); default: return 0; } }); } compare(a: number | string, b: number | string, isAsc: boolean): number { return (a < b ? -1 : 1) * (isAsc ? 1 : -1); } } <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 dt-button variant="secondary" (click)="disableSorting = !disableSorting" > Toggle disable sorting for all columns </button> export class TableSortingExample { disableSorting = false; dataSource = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, ]; sortData(event: DtSortEvent): void { const data = this.dataSource.slice(); this.dataSource = data.sort((a, b) => { const isAsc = event.direction === 'asc'; switch (event.active) { case 'host': return this.compare(a.host, b.host, isAsc); case 'cpu': return this.compare(a.cpu, b.cpu, isAsc); case 'memory': return this.compare(a.memoryPerc, b.memoryPerc, isAsc); case 'traffic': return this.compare(a.traffic, b.traffic, isAsc); default: return 0; } }); } compare(a: number | string, b: number | string, isAsc: boolean): number { return (a < b ? -1 : 1) * (isAsc ? 1 : -1); } }

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 column.
dtSortDisabled boolean false Whether sorting is disabled for the entire table.
dtSortStart DtSortDirection Sort direction in which a column is initially sorted. 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 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.

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.

´ Loading interactive demo...
<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> export class TableSearchExample implements OnInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memoryPerc: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memoryPerc: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memoryPerc: 12, memoryTotal: 2120000000, traffic: 4500000, }, ]; @ViewChild(DtTableSearch, { static: true }) tableSearch: DtTableSearch; searchValue = ''; dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngOnInit(): void { this.dataSource.search = this.tableSearch; } // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } } <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> export class TableSearchExample implements OnInit { data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memoryPerc: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memoryPerc: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memoryPerc: 12, memoryTotal: 2120000000, traffic: 4500000, }, ]; @ViewChild(DtTableSearch, { static: true }) tableSearch: DtTableSearch; searchValue = ''; dataSource: DtTableDataSource<object>; constructor() { this.dataSource = new DtTableDataSource(this.data); } ngOnInit(): void { this.dataSource.search = this.tableSearch; } // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } }

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.

´ Loading interactive demo...
<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> export class TablePaginationExample implements OnInit { private data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memoryPerc: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memoryPerc: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memoryPerc: 12, memoryTotal: 2120000000, traffic: 4500000, }, { host: 'dev-demo-5-macOS', cpu: 24, memoryPerc: 8.6, memoryTotal: 4670000000, traffic: 3270000, }, ]; // Get the viewChild to pass the sorter reference to the data-source. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; @ViewChild(DtPagination, { static: true }) pagination: DtPagination; 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 = 2; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } } <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> export class TablePaginationExample implements OnInit { private data: object[] = [ { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memoryPerc: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memoryPerc: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memoryPerc: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memoryPerc: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memoryPerc: 12, memoryTotal: 2120000000, traffic: 4500000, }, { host: 'dev-demo-5-macOS', cpu: 24, memoryPerc: 8.6, memoryTotal: 4670000000, traffic: 3270000, }, ]; // Get the viewChild to pass the sorter reference to the data-source. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; @ViewChild(DtPagination, { static: true }) pagination: DtPagination; 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 = 2; } percentageFormatter = formatPercent; trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); // tslint:disable-next-line: no-any combineMemory(row: any): string { const memoryPercentage = formatPercent(row.memoryPerc); const memoryTotal = formatBytes(row.memoryTotal, { inputUnit: 'byte', outputUnit: 'GB', factor: 1024, }); return `${memoryPercentage} of ${memoryTotal}`; } // tslint:disable-next-line: no-any memorySortAccessor(row: any): number { return row.memoryPerc; } }

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.

´ Loading interactive demo...
<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> <dt-show-more (click)="loadMore()"> Show 5 more </dt-show-more> export class TableShowMoreExample implements OnInit, OnDestroy { percentageFormatter = formatPercent; dataSource: DtTableDataSource<{ host: string; cpu: number; memory: number; traffic: number; }> = new DtTableDataSource(); @ViewChild(DtShowMore, { static: true }) showMore: DtShowMore; private destroy$ = new Subject<void>(); // tslint:disable-next-line:max-line-length private fakeBackend = new BehaviorSubject< Array<{ host: string; cpu: number; memory: number; memoryTotal: number; traffic: number; }> >([ { host: 'et-demo-2-win4', cpu: 30, memory: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memory: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memory: 35, memoryTotal: 5810000000, traffic: 41900000, }, ]); ngOnInit(): void { this.fakeBackend .pipe(takeUntil(this.destroy$)) .subscribe( ( data: Array<{ host: string; cpu: number; memory: number; traffic: number; }>, ) => { this.dataSource.data = data; }, ); } loadMore(): void { this.fakeBackend.next([ { host: 'et-demo-2-win4', cpu: 30, memory: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memory: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memory: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memory: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memory: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memory: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memory: 12, memoryTotal: 2120000000, traffic: 4500000, }, { host: 'dev-demo-5-macOS', cpu: 24, memory: 8.6, memoryTotal: 4670000000, traffic: 3270000, }, ]); this.showMore.disabled = true; } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); } <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> <dt-show-more (click)="loadMore()"> Show 5 more </dt-show-more> export class TableShowMoreExample implements OnInit, OnDestroy { percentageFormatter = formatPercent; dataSource: DtTableDataSource<{ host: string; cpu: number; memory: number; traffic: number; }> = new DtTableDataSource(); @ViewChild(DtShowMore, { static: true }) showMore: DtShowMore; private destroy$ = new Subject<void>(); // tslint:disable-next-line:max-line-length private fakeBackend = new BehaviorSubject< Array<{ host: string; cpu: number; memory: number; memoryTotal: number; traffic: number; }> >([ { host: 'et-demo-2-win4', cpu: 30, memory: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memory: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memory: 35, memoryTotal: 5810000000, traffic: 41900000, }, ]); ngOnInit(): void { this.fakeBackend .pipe(takeUntil(this.destroy$)) .subscribe( ( data: Array<{ host: string; cpu: number; memory: number; traffic: number; }>, ) => { this.dataSource.data = data; }, ); } loadMore(): void { this.fakeBackend.next([ { host: 'et-demo-2-win4', cpu: 30, memory: 38, memoryTotal: 5830000000, traffic: 98700000, }, { host: 'et-demo-2-win3', cpu: 26, memory: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'docker-host2', cpu: 25.4, memory: 35, memoryTotal: 5810000000, traffic: 41900000, }, { host: 'et-demo-2-win1', cpu: 23, memory: 7.86, memoryTotal: 5820000000, traffic: 98700000, }, { host: 'et-demo-2-win8', cpu: 78, memory: 21, memoryTotal: 3520000000, traffic: 91870000, }, { host: 'et-demo-2-macOS', cpu: 21, memory: 34, memoryTotal: 3200000000, traffic: 1200000, }, { host: 'kyber-host6', cpu: 12.3, memory: 12, memoryTotal: 2120000000, traffic: 4500000, }, { host: 'dev-demo-5-macOS', cpu: 24, memory: 8.6, memoryTotal: 4670000000, traffic: 3270000, }, ]); this.showMore.disabled = true; } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } trafficFormatter = (value: number) => formatBytes(formatRate(value, 's'), { inputUnit: 'byte', outputUnit: 'MB', factor: 1024, }); }

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({
  moduleId: module.id,
  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');
  }
}

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.

´ Loading interactive demo...
<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" 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="['host', 'cpu', 'memory', 'traffic', 'details']" ></dt-header-row> <dt-expandable-row *dtRowDef=" let row; columns: ['host', 'cpu', 'memory', 'traffic', 'details'] " [expanded]="row.expanded" > Expandable section for {{ row.host }} </dt-expandable-row> </dt-table> <button dt-button variant="secondary" (click)="multiExpand = !multiExpand"> Toggle multiexpand (current value: {{ multiExpand }}) </button> export class TableExpandableRowsExample { multiExpand = false; dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', expanded: true, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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" 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="['host', 'cpu', 'memory', 'traffic', 'details']" ></dt-header-row> <dt-expandable-row *dtRowDef=" let row; columns: ['host', 'cpu', 'memory', 'traffic', 'details'] " [expanded]="row.expanded" > Expandable section for {{ row.host }} </dt-expandable-row> </dt-table> <button dt-button variant="secondary" (click)="multiExpand = !multiExpand"> Toggle multiexpand (current value: {{ multiExpand }}) </button> export class TableExpandableRowsExample { multiExpand = false; dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', expanded: true, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }
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.

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 ariaLabel 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>

Content limitations

To guarantee a reasonable perception of the content in the content area (i.e. the expanded section), there are some limitations of controls which can be used:

Keep in mind to limit the content in expandable table rows for better visual perception. As a rule of thumb we recommend to keep the content height under 580px (estimated available height on a screen width of 1024px). If there is a lot of content, consider navigating to a details page.

Please keep in mind:

  • Do not put a table or an expandable in an expandable table!
  • Do not add content that requires any kind of pagination!

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.

´ Loading interactive demo...
<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> <dt-empty-state-item> <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> {{ 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 dt-button variant="secondary" (click)="toggleEmptyState()"> Toggle empty state </button> export class TableEmptyStateExample { data: object[] = [ { usersId: 'Alexander@sommers.at', sessionCount: 10, averageDuration: '13.6ms', errors: 6, country: 'Austria', city: 'Linz', browserFamily: 'Chrome', device: 'A1688', }, { usersId: 'maximilian@mustermann.at', sessionCount: 8, averageDuration: '9.99ms', errors: 0, country: 'Austria', city: 'Salzburg', browserFamily: 'Firefox', device: 'A1688', }, { usersId: 'karl@winter.at', sessionCount: 4, averageDuration: '9.55ms', errors: 1, country: 'Austria', city: 'Vienna', browserFamily: 'Firefox', device: 'A1688', }, ]; dataSource: object[] = []; emptyState = { title: 'No data that matches your query', message: `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`, }; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; toggleEmptyState(): void { this.dataSource = this.dataSource.length ? [] : [...this.data]; } } <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> <dt-empty-state-item> <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> {{ 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 dt-button variant="secondary" (click)="toggleEmptyState()"> Toggle empty state </button> export class TableEmptyStateExample { data: object[] = [ { usersId: 'Alexander@sommers.at', sessionCount: 10, averageDuration: '13.6ms', errors: 6, country: 'Austria', city: 'Linz', browserFamily: 'Chrome', device: 'A1688', }, { usersId: 'maximilian@mustermann.at', sessionCount: 8, averageDuration: '9.99ms', errors: 0, country: 'Austria', city: 'Salzburg', browserFamily: 'Firefox', device: 'A1688', }, { usersId: 'karl@winter.at', sessionCount: 4, averageDuration: '9.55ms', errors: 1, country: 'Austria', city: 'Vienna', browserFamily: 'Firefox', device: 'A1688', }, ]; dataSource: object[] = []; emptyState = { title: 'No data that matches your query', message: `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`, }; // Get the viewChild to pass the sorter reference to the datasource. @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort; toggleEmptyState(): void { this.dataSource = this.dataSource.length ? [] : [...this.data]; } }

Loading state

You can mark the table as loading using the table's loading input and pass the content to display with dtTableLoadingState directive.

´ Loading interactive demo...
<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 dt-button variant="secondary" (click)="tableLoading = !tableLoading" > Toggle loading property </button> export class TableLoadingExample { tableLoading = true; dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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 dt-button variant="secondary" (click)="tableLoading = !tableLoading" > Toggle loading property </button> export class TableLoadingExample { tableLoading = true; dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

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.

´ Loading interactive demo...
<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> &nbsp;of&nbsp; <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 dt-button variant="secondary" (click)="_toggleProblem()"> Toggle problem </button> export class TableProblemExample { _dataSource: TableData[] = [ { name: 'et-demo-2-win4', cpuUsage: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 987000000, warnings: ['memoryPerc'], errors: ['cpuUsage'], }, { name: 'et-demo-2-win3', cpuUsage: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 6250000000, }, { name: 'docker-host2', cpuUsage: 25.4, memoryPerc: 38, memoryTotal: 5250000000, traffic: 4190000000, warnings: ['cpuUsage'], }, { name: 'et-demo-2-win1', cpuUsage: 23, memoryPerc: 7.86, memoryTotal: 16000000000, traffic: 987000000, }, ]; metricHasProblem(rowData: TableData, metricName: string): boolean { return ( this._metricHasError(rowData, metricName) || this._metricHasWarning(rowData, metricName) ); } metricIndicatorColor( rowData: TableData, metricName: string, ): 'error' | 'warning' | null { return this._metricHasError(rowData, metricName) ? 'error' : this._metricHasWarning(rowData, metricName) ? 'warning' : null; } private _metricHasError(rowData: TableData, metricName: string): boolean { return rowData.errors !== undefined && rowData.errors.includes(metricName); } private _metricHasWarning(rowData: TableData, metricName: string): boolean { return ( rowData.warnings !== undefined && rowData.warnings.includes(metricName) ); } _toggleProblem(): void { if (this._dataSource[0].errors) { delete this._dataSource[0].errors; } else { this._dataSource[0].errors = ['cpuUsage']; } } } <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> &nbsp;of&nbsp; <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 dt-button variant="secondary" (click)="_toggleProblem()"> Toggle problem </button> export class TableProblemExample { _dataSource: TableData[] = [ { name: 'et-demo-2-win4', cpuUsage: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 987000000, warnings: ['memoryPerc'], errors: ['cpuUsage'], }, { name: 'et-demo-2-win3', cpuUsage: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 6250000000, }, { name: 'docker-host2', cpuUsage: 25.4, memoryPerc: 38, memoryTotal: 5250000000, traffic: 4190000000, warnings: ['cpuUsage'], }, { name: 'et-demo-2-win1', cpuUsage: 23, memoryPerc: 7.86, memoryTotal: 16000000000, traffic: 987000000, }, ]; metricHasProblem(rowData: TableData, metricName: string): boolean { return ( this._metricHasError(rowData, metricName) || this._metricHasWarning(rowData, metricName) ); } metricIndicatorColor( rowData: TableData, metricName: string, ): 'error' | 'warning' | null { return this._metricHasError(rowData, metricName) ? 'error' : this._metricHasWarning(rowData, metricName) ? 'warning' : null; } private _metricHasError(rowData: TableData, metricName: string): boolean { return rowData.errors !== undefined && rowData.errors.includes(metricName); } private _metricHasWarning(rowData: TableData, metricName: string): boolean { return ( rowData.warnings !== undefined && rowData.warnings.includes(metricName) ); } _toggleProblem(): void { if (this._dataSource[0].errors) { delete this._dataSource[0].errors; } else { this._dataSource[0].errors = ['cpuUsage']; } } }

Advanced usage

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>
´ Loading interactive demo...
<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> export class TableStickyHeaderExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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> export class TableStickyHeaderExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

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.

´ Loading interactive demo...
<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> export class TableColumnProportionExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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> export class TableColumnProportionExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

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.

´ Loading interactive demo...
<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> export class TableColumnMinWidthExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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> export class TableColumnMinWidthExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

Dynamic columns

You can bind the column definitions to an array with a *ngFor directive.

´ Loading interactive demo...
<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> export class TableDynamicColumnsExample { columnsDef = [ { id: 'host', title: 'Host', type: 'text', }, { id: 'cpu', title: 'CPU', type: 'number', }, { id: 'memory', title: 'Memory', type: 'number', }, { id: 'traffic', title: 'Traffic', type: 'number', }, ]; columnsName = this.columnsDef.map(col => col.id); dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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> export class TableDynamicColumnsExample { columnsDef = [ { id: 'host', title: 'Host', type: 'text', }, { id: 'cpu', title: 'CPU', type: 'number', }, { id: 'memory', title: 'Memory', type: 'number', }, { id: 'traffic', title: 'Traffic', type: 'number', }, ]; columnsName = this.columnsDef.map(col => col.id); dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

Interactive rows

To apply a hover effect for the table rows add interactiveRows on the dt-table component.

´ Loading interactive demo...
<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> export class TableInteractiveRowsExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; } <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> export class TableInteractiveRowsExample { dataSource: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', }, ]; }

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.

´ Loading interactive demo...
<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> export class TableWithInfoGroupCellExample { dataSource: object[] = [ { service: 'BookingService', location: 'ruxit-dev-us-east-BB', responseTime: 72, failureRate: 0, }, { service: 'EasyTravelWebserver:8079', location: 'ruxti-dev-us-east-THIRD', responseTime: 71.3, failureRate: 0.9, }, { service: 'easyTRavelBusiness', location: 'gn-rx-ub12-cl04v.clients.emeea.cpwr.corp', responseTime: 66.2, failureRate: 0.1, }, { service: 'easyTravel', location: 'L-W864-APMDay3', responseTime: 44, failureRate: 0, }, ]; } <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> export class TableWithInfoGroupCellExample { dataSource: object[] = [ { service: 'BookingService', location: 'ruxit-dev-us-east-BB', responseTime: 72, failureRate: 0, }, { service: 'EasyTravelWebserver:8079', location: 'ruxti-dev-us-east-THIRD', responseTime: 71.3, failureRate: 0.9, }, { service: 'easyTRavelBusiness', location: 'gn-rx-ub12-cl04v.clients.emeea.cpwr.corp', responseTime: 66.2, failureRate: 0.1, }, { service: 'easyTravel', location: 'L-W864-APMDay3', responseTime: 44, failureRate: 0, }, ]; }

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.

´ Loading interactive demo...
<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="number"> <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: !isNarrow " ></dt-row> <dt-expandable-row *dtRowDef=" let row; columns: ['host', 'cpu', 'details']; let rowIndex = index; when: isNarrow " > <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> </dt-expandable-row> </dt-table> export class TableResponsiveExample { dataSource: HostMetricResponsive[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', isNarrow: false, }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', isNarrow: false, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', isNarrow: false, }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', isNarrow: false, }, ]; _headerColumns = new Set(['host', 'cpu']); isNarrow(_: number, row: HostMetricResponsive): boolean { return row.isNarrow; } constructor( private _viewportResizer: DtViewportResizer, private _viewportRuler: ViewportRuler, private _zone: NgZone, ) { this._viewportResizer .change() .pipe( startWith(null), switchMap(() => this._zone.onStable.pipe(take(1))), ) .subscribe(() => { const narrow = this._viewportRuler.getViewportSize().width < NARROW_THRESHHOLD ? true : false; if (this.dataSource[0].isNarrow !== narrow) { this.dataSource = this.dataSource.map(data => { data.isNarrow = narrow; return data; }); } if (narrow) { this._headerColumns.delete('memory'); this._headerColumns.delete('traffic'); this._headerColumns.add('details'); } else { this._headerColumns.add('memory'); this._headerColumns.add('traffic'); this._headerColumns.delete('details'); } }); } } <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="number"> <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: !isNarrow " ></dt-row> <dt-expandable-row *dtRowDef=" let row; columns: ['host', 'cpu', 'details']; let rowIndex = index; when: isNarrow " > <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> </dt-expandable-row> </dt-table> export class TableResponsiveExample { dataSource: HostMetricResponsive[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', isNarrow: false, }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', isNarrow: false, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', isNarrow: false, }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', isNarrow: false, }, ]; _headerColumns = new Set(['host', 'cpu']); isNarrow(_: number, row: HostMetricResponsive): boolean { return row.isNarrow; } constructor( private _viewportResizer: DtViewportResizer, private _viewportRuler: ViewportRuler, private _zone: NgZone, ) { this._viewportResizer .change() .pipe( startWith(null), switchMap(() => this._zone.onStable.pipe(take(1))), ) .subscribe(() => { const narrow = this._viewportRuler.getViewportSize().width < NARROW_THRESHHOLD ? true : false; if (this.dataSource[0].isNarrow !== narrow) { this.dataSource = this.dataSource.map(data => { data.isNarrow = narrow; return data; }); } if (narrow) { this._headerColumns.delete('memory'); this._headerColumns.delete('traffic'); this._headerColumns.add('details'); } else { this._headerColumns.add('memory'); this._headerColumns.add('traffic'); this._headerColumns.delete('details'); } }); } }

Observable as data source

You can pass an observable to the [dataSource] property.

´ Loading interactive demo...
<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-table> <button dt-button (click)="startSubscription()">Start subscription</button> <button dt-button variant="secondary" (click)="clearRows()">Clear</button> export class TableObservableExample { dataSource = new BehaviorSubject<object[]>([]); // tslint:disable-next-line:no-magic-numbers private source = interval(1000); subscription: Subscription; startSubscription(): void { this.subscription = this.source.pipe(take(MAX_ROWS)).subscribe((): void => { this.getAnotherRow(); }); } clearRows(): void { this.dataSource.next([]); } getAnotherRow(): void { // tslint:disable this.dataSource.next([ ...this.dataSource.value, { host: 'et-demo-2-win4', cpu: `${(Math.random() * 10).toFixed(2)} %`, memory: `${(Math.random() * 10).toFixed(2)} % of ${( Math.random() * 40 ).toFixed(2)} GB`, traffic: `${(Math.random() * 100).toFixed(2)} Mbit/s`, }, ]); // tslint:enable } } <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-table> <button dt-button (click)="startSubscription()">Start subscription</button> <button dt-button variant="secondary" (click)="clearRows()">Clear</button> export class TableObservableExample { dataSource = new BehaviorSubject<object[]>([]); // tslint:disable-next-line:no-magic-numbers private source = interval(1000); subscription: Subscription; startSubscription(): void { this.subscription = this.source.pipe(take(MAX_ROWS)).subscribe((): void => { this.getAnotherRow(); }); } clearRows(): void { this.dataSource.next([]); } getAnotherRow(): void { // tslint:disable this.dataSource.next([ ...this.dataSource.value, { host: 'et-demo-2-win4', cpu: `${(Math.random() * 10).toFixed(2)} %`, memory: `${(Math.random() * 10).toFixed(2)} % of ${( Math.random() * 40 ).toFixed(2)} GB`, traffic: `${(Math.random() * 100).toFixed(2)} Mbit/s`, }, ]); // tslint:enable } }

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>

Tables in use

Buttons or switches in tables

  • It is possible to use buttons in tables, but should be used sparingly.
  • Switches in tables (e.g. to enable/disable monitoring of an entity) are vertically centered in the table row.

Charts in tables

Micro bar charts can be used in tables to visualize information and enable easy comparison. Keep the number of bar charts to one and explain the chart with an appropriate table header. The metric can be added in the same column. For good legibility the metric should be right aligned in front of the bar chart.

Micro bar charts in tables

Colors are always dependent on the environment the chart is in theme colors.

Tables in Overlays

It is possible to use overlays with tables.