Table

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]="dataSource1"> <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; index as i; count as c; first as f; last as l; even as e; odd as o " > Row {{ i }}/{{ c }} {{ e ? 'even' : 'odd' }}: {{ row.cpu }} {{ f ? 'first' : '' }} {{ l ? 'last' : '' }} </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']; index as i; count as c; first as f; last as l; even as e; odd as o " (click)="rowClicked(row, i, c)" ></dt-row> </dt-table> export class TableDefaultExample { dataSource1: 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', }, ]; rowClicked(row: object, index: number, count: number): void { // tslint:disable-next-line LOG.debug(`row ${index}/${count} clicked`, row); } } <dt-table [dataSource]="dataSource1"> <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; index as i; count as c; first as f; last as l; even as e; odd as o " > Row {{ i }}/{{ c }} {{ e ? 'even' : 'odd' }}: {{ row.cpu }} {{ f ? 'first' : '' }} {{ l ? 'last' : '' }} </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']; index as i; count as c; first as f; last as l; even as e; odd as o " (click)="rowClicked(row, i, c)" ></dt-row> </dt-table> export class TableDefaultExample { dataSource1: 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', }, ]; rowClicked(row: object, index: number, count: number): void { // tslint:disable-next-line LOG.debug(`row ${index}/${count} clicked`, row); } }

Alignment in tables

Header text should always follow the same alignment as the column content.

Left-aligned content

  • Text
  • Identification numbers beginning with letters. E.g. ID

Center-aligned content

  • Icons
  • Interactive components (e.g. switches)

Right-aligned content

  • Numbers
  • Date, Time, Year,...
  • IP addresses

States

Hover on table header

´ Loading interactive demo...
<dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" > <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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <dt-header-cell *dtHeaderCellDef 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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingExample { dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { 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)" > <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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <dt-header-cell *dtHeaderCellDef 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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingExample { dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { 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); } }

Hover on table row

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1" 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="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> export class TableHoverExample { dataSource1: 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]="dataSource1" 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="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> export class TableHoverExample { dataSource1: 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', }, ]; }

Selected

Selection behavior
border-width: 1px //inside
border-color: theme color shade 500

Variants

Tables with two lines per row

´ 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="agent"></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="agent"></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, }, ]; }

Expandable table

To show more details in context of a single table row, use an expandable table. To guarantee a reasonable perception of the content in the content area, there are some limitations of controls which can be used:

Keep in mind to limit the content in expandable tables 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!
´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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']; let rowIndex = index " > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableExpandableRowsExample { dataSource1: 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]="dataSource1"> <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']; let rowIndex = index " > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableExpandableRowsExample { dataSource1: 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', }, ]; }

Empty tables

If a table is empty, the information about the reason is shown with the table like in the example here. An illustration can help to visualize the problem.

´ Loading interactive demo...
<button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <ng-container dtColumnDef="usersId" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Users ID</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.usersId }}</dt-cell> </ng-container> <ng-container dtColumnDef="sessionCount" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Session count</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.sessionCount }}</dt-cell> </ng-container> <ng-container dtColumnDef="averageDuration" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Average duration</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.averageDuration }}</dt-cell> </ng-container> <ng-container dtColumnDef="errors" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Errors</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.errors }}</dt-cell> </ng-container> <ng-container dtColumnDef="country" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Country</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.country }}</dt-cell> </ng-container> <ng-container dtColumnDef="city" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>City</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.city }}</dt-cell> </ng-container> <ng-container dtColumnDef="browserFamily" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Browser Family</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.browserFamily }}</dt-cell> </ng-container> <ng-container dtColumnDef="device" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Device</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.device }}</dt-cell> </ng-container> <dt-table-empty-state dtTableEmptyState> <dt-table-empty-state-image> <img alt="glass" src="data:image/png;base64,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" /> </dt-table-empty-state-image> <dt-table-empty-state-title> No data that matches your query </dt-table-empty-state-title> <dt-table-empty-state-message> {{ message }} </dt-table-empty-state-message> </dt-table-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> export class TableEmptyStateExample { dataSource: 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', }, ]; dataSource1: object[] = []; message = `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } } <button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <ng-container dtColumnDef="usersId" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Users ID</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.usersId }}</dt-cell> </ng-container> <ng-container dtColumnDef="sessionCount" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Session count</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.sessionCount }}</dt-cell> </ng-container> <ng-container dtColumnDef="averageDuration" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Average duration</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.averageDuration }}</dt-cell> </ng-container> <ng-container dtColumnDef="errors" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Errors</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.errors }}</dt-cell> </ng-container> <ng-container dtColumnDef="country" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Country</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.country }}</dt-cell> </ng-container> <ng-container dtColumnDef="city" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>City</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.city }}</dt-cell> </ng-container> <ng-container dtColumnDef="browserFamily" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Browser Family</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.browserFamily }}</dt-cell> </ng-container> <ng-container dtColumnDef="device" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Device</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.device }}</dt-cell> </ng-container> <dt-table-empty-state dtTableEmptyState> <dt-table-empty-state-image> <img alt="glass" src="data:image/png;base64,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" /> </dt-table-empty-state-image> <dt-table-empty-state-title> No data that matches your query </dt-table-empty-state-title> <dt-table-empty-state-message> {{ message }} </dt-table-empty-state-message> </dt-table-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> export class TableEmptyStateExample { dataSource: 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', }, ]; dataSource1: object[] = []; message = `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } }

Problem state indication

Use the red status color for highlighting problematic elements.

Single metric problem indication

If a single metric in a table entry is affected, use the red status color to highlight only the affected value.

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 can be highlighted in red.

Note: Don't color hyperlinks even if the whole entity is affected, in this case use only the red indicator.

´ 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="text"> <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="control"> <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 (click)="_toggleProblem()">Toggle problem</button> export class TableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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="text"> <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="control"> <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 (click)="_toggleProblem()">Toggle problem</button> export class TableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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']; } } }

The example above shows both usages - single metric inside a cell and the entire cell.

Behavior

Sorting

If a column is sortable, it must have the sorting indicator. An indicator can either be active (ascending or descending) or inactive. The table component has the ability to change the ordering characteristics of the table at initialisation time. It is important to consider the use cases and select what you'd want to happen on 'first click'.

´ Loading interactive demo...
<button dt-button (click)="toggleDisableAll()"> Toggle disable sorting for all columns </button> <dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" [dtSortDisabled]="disableAll" [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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingFullExample { disableAll = false; dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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); } toggleDisableAll(): void { this.disableAll = !this.disableAll; } } <button dt-button (click)="toggleDisableAll()"> Toggle disable sorting for all columns </button> <dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" [dtSortDisabled]="disableAll" [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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingFullExample { disableAll = false; dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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); } toggleDisableAll(): void { this.disableAll = !this.disableAll; } }

Edit a table entry

The table component supports two edit modes:

  • Edit within the expandable table, indicated by the dropdown open icon in a table header named 'edit'.
  • Redirect to a separate edit page, indicated by the edit icon, for more complex forms.

Please use the nested button within the table row.

All input fields, as well as update and cancel buttons are then within the expanded table row. The update button gets enabled as soon as changes are made. Triggering either of the buttons, the table row is updated and collapses again.

Edit within expanded table

Delete a table entry

Use remove as a table column header if this action can be reverted (means the value is not in the list any more, but still not deleted). Use delete as a table column header if the value definitely is going to be deleted from the table. The abort icon used in the nested button triggers the remove or delete action.

Delete a table entry
x: 40px
y: 12px
z: 8px

Create a table entry

With the create or add button on top of the table a new table row can be added. The form to create a new table entry replaces the button.

Create a table entry
x: 20px
y: 32px
Form for creating a table entry
x: 16px
y: 20px
z: 60px
border top: 2px line, $gray-200
border bottom:: 2px line, $gray-200
background-color: $gray-100

Move up/down

For tables where the sorting of the rows is crucial (e.g. Process group detection rules) the sorter up and sorter down icons are used in a nested button to move rows.

Move up and down of table rows
width: 20px
height: 20px
icon color: $turquoise-600

Filtering in tables

By default, a filter icon and the watermark Filter this table indicate the filter action. The filter is only applied to the table underneath. As soon as filter is focused, an input field appears. The matching text is highlighted in the table entries.

´ 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"> <dt-highlight [term]="value">{{ 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">{{ 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> <input dtInput [dtAutocomplete]="auto" [(ngModel)]="value" (ngModelChange)="filter()" placeholder="Start typing" /> <dt-autocomplete #auto="dtAutocomplete"> <dt-option *ngFor="let option of filterableValues" [value]="option"> {{ option }} </dt-option> </dt-autocomplete> export class TableFilteringExample { private data: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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, }, ]; value: string; dataSource: DtTableDataSource<object>; get filterableValues(): string[] { return this.data.map( (data: { host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }) => data.host ); } constructor() { this.dataSource = new DtTableDataSource(this.data); } filter(): void { this.dataSource.filter = this.value; } } <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]="value">{{ 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">{{ 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> <input dtInput [dtAutocomplete]="auto" [(ngModel)]="value" (ngModelChange)="filter()" placeholder="Start typing" /> <dt-autocomplete #auto="dtAutocomplete"> <dt-option *ngFor="let option of filterableValues" [value]="option"> {{ option }} </dt-option> </dt-autocomplete> export class TableFilteringExample { private data: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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, }, ]; value: string; dataSource: DtTableDataSource<object>; get filterableValues(): string[] { return this.data.map( (data: { host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }) => data.host ); } constructor() { this.dataSource = new DtTableDataSource(this.data); } filter(): void { this.dataSource.filter = this.value; } }

Tables in use

On smaller screens the table converts to an expandable table containing the most right columns as key-value pairs until the width fits the screen.

´ 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'); } }); } }

Buttons or switches in tables

It is possible to use buttons in tables. Buttons can also appear on hover. 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
x: 8px
y: 16px

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

Tables in Overlays

It is possible to use tables in overlays.

The DtTable enhances the Material's cdk table. This first implementation also removes unneeded things from the public API.

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

@NgModule({
  imports: [
    BrowserAnimationsModule
    DtTableModule,
  ],
})
class MyModule {}

Component and attribute directives for the table:

Component/Attribute Type Description
dtColumnDef Attribute Name for the column (to be used in the header and row definitions)
dtColumnAlign Attribute Type for the column (to be used in the alignment and for future versions add pipes and masks), possible values are: left-alignment ['left', 'text', 'id'], center-alignment ['center', 'icon', 'control'], right-alignment ['right', 'number', 'date', 'ip']
dtColumnProportion Attribute A number describing the width proportion for the column. [dtColumnProportion]=2 means that this column's width will be doubled compared to the regular ones
dtColumnMinWidth Attribute A CSS string describing the minimum width for the column. [dtColumnMinWidth]="'200px'" means that this column's width will be at least 200px
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)
dt-expandable-cell Component Adds the appropriate classes, role and content for the details cell in an expandable 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
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
*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
dtTableEmptyState Directive Placeholder for the content displayed when the table is empty
dt-table-empty-state Component Placeholder for the formatted content displayed when the table is empty
dt-table-empty-state-image Component Placeholder for the image or icon to use within the <dt-table-empty-table>
dt-table-empty-state-title Component Placeholder for the title to use within the <dt-table-empty-table>
dt-table-empty-state-message Component Placeholder for the message to use within the <dt-table-empty-table>
dtTableLoadingState Directive Placeholder for the content displayed when the table is loading

Inputs

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.

There are no outputs at this stage. The table is totally passive.

Table Usage

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 is no td, tr or th involved. Instead, you need to define all possible columns that the table may show (depending on the data available) and then define the table header and body by selecting from the column definitions, which subset of columns you want to show.

Each column definition is created with dt-header-cell and dt-cell inside a 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}}</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></dt-header-row>
</dt-header-row>

To make the header sticky, add the dtHeaderRowDefSticky input to the dtHeaderRowDef directive.

<dt-header-row *dtHeaderRowDef="['username', 'age', 'title']; sticky">
  <dt-header-row></dt-header-row>
</dt-header-row>

And 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 any of the examples in this page to see all the pieces in place.

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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; index as i; count as c; first as f; last as l; even as e; odd as o " > Row {{ i }}/{{ c }} {{ e ? 'even' : 'odd' }}: {{ row.cpu }} {{ f ? 'first' : '' }} {{ l ? 'last' : '' }} </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']; index as i; count as c; first as f; last as l; even as e; odd as o " (click)="rowClicked(row, i, c)" ></dt-row> </dt-table> export class TableDefaultExample { dataSource1: 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', }, ]; rowClicked(row: object, index: number, count: number): void { // tslint:disable-next-line LOG.debug(`row ${index}/${count} clicked`, row); } } <dt-table [dataSource]="dataSource1"> <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; index as i; count as c; first as f; last as l; even as e; odd as o " > Row {{ i }}/{{ c }} {{ e ? 'even' : 'odd' }}: {{ row.cpu }} {{ f ? 'first' : '' }} {{ l ? 'last' : '' }} </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']; index as i; count as c; first as f; last as l; even as e; odd as o " (click)="rowClicked(row, i, c)" ></dt-row> </dt-table> export class TableDefaultExample { dataSource1: 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', }, ]; rowClicked(row: object, index: number, count: number): void { // tslint:disable-next-line LOG.debug(`row ${index}/${count} clicked`, row); } }

Width proportion

You can customize the column width proportion with the [dtColumnProportion] attribute.

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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="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> export class TableDifferentWidthExample { dataSource1: 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]="dataSource1"> <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="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> export class TableDifferentWidthExample { dataSource1: 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="agent"></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="agent"></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, }, ]; }

Minimum Width

You can customize the column minimun width with [dtColumnMinWidth]

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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="text" 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="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> export class TableMinWidthExample { dataSource1: 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]="dataSource1"> <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="text" 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="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> export class TableMinWidthExample { dataSource1: 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', }, ]; }

Empty state

You can pass an empty state to the table using the dtTableEmptyState directive, this will be used when there's no data. The recommended approach is to use the following components: <dt-table-empty-state>, <dt-table-empty-state-image>, <dt-table-empty-state-title>, <dt-table-empty-state-message>

´ Loading interactive demo...
<button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <ng-container dtColumnDef="usersId" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Users ID</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.usersId }}</dt-cell> </ng-container> <ng-container dtColumnDef="sessionCount" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Session count</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.sessionCount }}</dt-cell> </ng-container> <ng-container dtColumnDef="averageDuration" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Average duration</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.averageDuration }}</dt-cell> </ng-container> <ng-container dtColumnDef="errors" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Errors</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.errors }}</dt-cell> </ng-container> <ng-container dtColumnDef="country" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Country</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.country }}</dt-cell> </ng-container> <ng-container dtColumnDef="city" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>City</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.city }}</dt-cell> </ng-container> <ng-container dtColumnDef="browserFamily" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Browser Family</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.browserFamily }}</dt-cell> </ng-container> <ng-container dtColumnDef="device" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Device</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.device }}</dt-cell> </ng-container> <dt-table-empty-state dtTableEmptyState> <dt-table-empty-state-image> <img alt="glass" src="data:image/png;base64,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" /> </dt-table-empty-state-image> <dt-table-empty-state-title> No data that matches your query </dt-table-empty-state-title> <dt-table-empty-state-message> {{ message }} </dt-table-empty-state-message> </dt-table-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> export class TableEmptyStateExample { dataSource: 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', }, ]; dataSource1: object[] = []; message = `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } } <button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <ng-container dtColumnDef="usersId" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Users ID</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.usersId }}</dt-cell> </ng-container> <ng-container dtColumnDef="sessionCount" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Session count</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.sessionCount }}</dt-cell> </ng-container> <ng-container dtColumnDef="averageDuration" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Average duration</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.averageDuration }}</dt-cell> </ng-container> <ng-container dtColumnDef="errors" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Errors</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.errors }}</dt-cell> </ng-container> <ng-container dtColumnDef="country" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Country</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.country }}</dt-cell> </ng-container> <ng-container dtColumnDef="city" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>City</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.city }}</dt-cell> </ng-container> <ng-container dtColumnDef="browserFamily" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Browser Family</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.browserFamily }}</dt-cell> </ng-container> <ng-container dtColumnDef="device" dtColumnAlign="text"> <dt-header-cell *dtHeaderCellDef>Device</dt-header-cell> <dt-cell *dtCellDef="let row">{{ row.device }}</dt-cell> </ng-container> <dt-table-empty-state dtTableEmptyState> <dt-table-empty-state-image> <img alt="glass" src="data:image/png;base64,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" /> </dt-table-empty-state-image> <dt-table-empty-state-title> No data that matches your query </dt-table-empty-state-title> <dt-table-empty-state-message> {{ message }} </dt-table-empty-state-message> </dt-table-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> export class TableEmptyStateExample { dataSource: 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', }, ]; dataSource1: object[] = []; message = `Amend the timefrime you're querying within or review your query to make your statement less restrictive.`; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } }

You can also pass custom content using the same dtTableEmptyState.

´ Loading interactive demo...
<button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <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> <div dtTableEmptyState style="width: 100%; text-align:center; margin: 3em 0;" > This is the custom content passed. </div> <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 TableEmptyCustomStateExample { 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', }, ]; dataSource1: object[] = []; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } } <button (click)="toggleEmptyState()">Toggle empty state</button> <dt-table [dataSource]="dataSource1"> <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> <div dtTableEmptyState style="width: 100%; text-align:center; margin: 3em 0;" > This is the custom content passed. </div> <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 TableEmptyCustomStateExample { 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', }, ]; dataSource1: object[] = []; toggleEmptyState(): void { this.dataSource1 = this.dataSource1.length ? [] : [...this.dataSource]; } }

Loading state

You can mark the table as loading using [loading] and pass the content to display with dtTableLoadingState directive

´ Loading interactive demo...
<button (click)="toggleLoading()">Toggle loading property</button> <dt-table [dataSource]="dataSource1" [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="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-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> export class TableLoadingExample { dataSource1: 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', }, ]; tableLoading = true; toggleLoading(): void { this.tableLoading = !this.tableLoading; } } <button (click)="toggleLoading()">Toggle loading property</button> <dt-table [dataSource]="dataSource1" [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="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-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> export class TableLoadingExample { dataSource1: 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', }, ]; tableLoading = true; toggleLoading(): void { this.tableLoading = !this.tableLoading; } }

Observable as DataSource

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

´ Loading interactive demo...
<button (click)="startSubscription()">Start subscription</button> <button (click)="clearRows()">Clear</button> <dt-table [dataSource]="dataSource1"> <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> export class TableObservableExample { dataSource1 = new BehaviorSubject<object[]>([]); emptyTitle = 'No Host'; emptyMessage = `from 9:00 - 10:00\n Remove filter to make your search less restrictive. Expand or change the timeframe you're searching within.`; // 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.dataSource1.next([]); } getAnotherRow(): void { // tslint:disable this.dataSource1.next([ ...this.dataSource1.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 } } <button (click)="startSubscription()">Start subscription</button> <button (click)="clearRows()">Clear</button> <dt-table [dataSource]="dataSource1"> <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> export class TableObservableExample { dataSource1 = new BehaviorSubject<object[]>([]); emptyTitle = 'No Host'; emptyMessage = `from 9:00 - 10:00\n Remove filter to make your search less restrictive. Expand or change the timeframe you're searching within.`; // 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.dataSource1.next([]); } getAnotherRow(): void { // tslint:disable this.dataSource1.next([ ...this.dataSource1.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 } }

Dynamic Columns

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

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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: 'text', }, { id: 'memory', title: 'Memory', type: 'number', }, { id: 'traffic', title: 'Traffic', type: 'control', }, ]; columnsName = this.columnsDef.map(col => col.id); dataSource1: 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]="dataSource1"> <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: 'text', }, { id: 'memory', title: 'Memory', type: 'number', }, { id: 'traffic', title: 'Traffic', type: 'control', }, ]; columnsName = this.columnsDef.map(col => col.id); dataSource1: 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 DataSource type is an abstract class with two methods: connect and disconnect. Connect has to return an Observable that the table subscribes to. Disconnect does cleanup. Using this class to wrap the data provided for the table allows maximum flexibility and will be responsible of a future sort, and filter functionalities.

Expandable Table Rows

Expandable rows can be defined using dt-expandable-row. 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]="dataSource1"> <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']; let rowIndex = index " > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableExpandableRowsExample { dataSource1: 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]="dataSource1"> <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']; let rowIndex = index " > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableExpandableRowsExample { dataSource1: 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', }, ]; }

Multiple rows can be expanded at a time. The expanded state of each row can be set programmatically.

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1" [multiExpand]="true"> <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']; let rowIndex = index " [expanded]="row.expanded" > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableMultiExpandableRowsExample { dataSource1: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', expanded: true, }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', expanded: false, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', expanded: false, }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', expanded: true, }, ]; } <dt-table [dataSource]="dataSource1" [multiExpand]="true"> <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']; let rowIndex = index " [expanded]="row.expanded" > Expandable section for {{ row.name }} </dt-expandable-row> </dt-table> export class TableMultiExpandableRowsExample { dataSource1: object[] = [ { host: 'et-demo-2-win4', cpu: '30 %', memory: '38 % of 5.83 GB', traffic: '98.7 Mbit/s', expanded: true, }, { host: 'et-demo-2-win3', cpu: '26 %', memory: '46 % of 6 GB', traffic: '625 Mbit/s', expanded: false, }, { host: 'docker-host2', cpu: '25.4 %', memory: '38 % of 5.83 GB', traffic: '419 Mbit/s', expanded: false, }, { host: 'et-demo-2-win1', cpu: '23 %', memory: '7.86 % of 5.83 GB', traffic: '98.7 Mbit/s', expanded: true, }, ]; }

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.

Options and Properties of DtExpandableCell

Expandable rows have to contain one column definition which contains a dt-expandable-cell. A sample column definition for the details column could look like this:

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

Inputs

Name Type Default Description
ariaLabel string Aria label that describes the action of toggling the state of the expandble-row.

Programmatic access

Through the table object

  • addColumnDef()
  • removeColumnDef()
  • addRowDef()
  • removeRowDef()
  • renderRows()
  • setHeaderRowDef()

Through the header object

  • getColumnsDiff()

Theming

The table styling depends on the page theme. You can set a theme on an area of the app by using the dtTheme directive.

To apply a sticky header to the table set the sticky input on the dtHeaderRowDef directive.

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1"> <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']; sticky: true" ></dt-header-row> <dt-row *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']" ></dt-row> </dt-table> export class TableStickyHeaderExample { dataSource1: 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]="dataSource1"> <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']; sticky: true" ></dt-header-row> <dt-row *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']" ></dt-row> </dt-table> export class TableStickyHeaderExample { dataSource1: 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', }, ]; }

Table hover

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

´ Loading interactive demo...
<dt-table [dataSource]="dataSource1" 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="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> export class TableHoverExample { dataSource1: 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]="dataSource1" 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="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> export class TableHoverExample { dataSource1: 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', }, ]; }

Sorting

´ Loading interactive demo...
<dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" > <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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <dt-header-cell *dtHeaderCellDef 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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingExample { dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { 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)" > <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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <dt-header-cell *dtHeaderCellDef 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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingExample { dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { host: 'et-demo-2-win3', cpu: 26, memoryPerc: 46, memoryTotal: 6000000000, traffic: 62500000, }, { host: 'et-demo-2-win4', cpu: 30, memoryPerc: 38, memoryTotal: 5830000000, traffic: 98700000, }, { 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); } }

The DtSort and dt-sort-header are used to add sorting functionality to the table.

To add sorting capabilities to your table add the dtSort directive to the dt-table component. 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-table ... dtSort ...></dt-table>

And use the dt-sort-header component for the header cells.

<dt-header-cell dt-sort-header ...></dt-header-cell>

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

To see a combination with initial sort direction and active column and disabling behaviour - please see the following complex example.

´ Loading interactive demo...
<button dt-button (click)="toggleDisableAll()"> Toggle disable sorting for all columns </button> <dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" [dtSortDisabled]="disableAll" [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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingFullExample { disableAll = false; dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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); } toggleDisableAll(): void { this.disableAll = !this.disableAll; } } <button dt-button (click)="toggleDisableAll()"> Toggle disable sorting for all columns </button> <dt-table [dataSource]="dataSource" dtSort (dtSortChange)="sortData($event)" [dtSortDisabled]="disableAll" [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="text"> <dt-header-cell *dtHeaderCellDef dt-sort-header sort-aria-label="Change sort order for cpus" > CPU </dt-header-cell> <dt-cell *dtCellDef=" let row; index as i; count as c; first as f; last as l; even as e; odd as o " > {{ 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="control"> <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']; index as i; count as c; first as f; last as l; even as e; odd as o " ></dt-row> </dt-table> export class TableSortingFullExample { disableAll = false; dataSource: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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); } toggleDisableAll(): void { this.disableAll = !this.disableAll; } }

Problem & Warning Indicator

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 color error set the indicator on the row is an error indicator (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>

The full example below shows both usages - single metric inside a cell and the entire cell enhanced with the dtIndicator for table with either static and expandable rows.

´ 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="text"> <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="control"> <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 (click)="_toggleProblem()">Toggle problem</button> export class TableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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="text"> <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="control"> <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 (click)="_toggleProblem()">Toggle problem</button> export class TableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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']; } } }
´ 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="text"> <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="control"> <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> <ng-container dtColumnDef="details" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell> <dt-expandable-cell *dtCellDef ariaLabel="Expand the row to see problem details" ></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'] " ></dt-expandable-row> </dt-table> <button dt-button (click)="_toggleProblem()">Toggle problem</button> export class TableExpandableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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="text"> <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="control"> <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> <ng-container dtColumnDef="details" dtColumnAlign="number"> <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell> <dt-expandable-cell *dtCellDef ariaLabel="Expand the row to see problem details" ></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'] " ></dt-expandable-row> </dt-table> <button dt-button (click)="_toggleProblem()">Toggle problem</button> export class TableExpandableProblemExample { _dataSource: TableData[] = [ // tslint:disable-next-line: max-line-length { 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']; } } }

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'); } }); } }

All pending functionality will be progressively addressed by future versions

Simple Columns

The dtSimpleColumn are 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.

Inputs

The dtSimpleColumn provides a couple of inputs, which give the user easy access to certain functionality of the dtTable like sorting, formatting, error/warning indicators.

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. If a sortable dtSimpleColumn is used within a table, the table needs the dtSort directive.
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)

Versions

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 alignemnt is set to number -> right
  • When no formatter is given, the dtCount formatter will automatically be applied, e.g. 1000 -> 1k

Example

´ 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" ></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" [hasProblem]="trafficHasProblem" ></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 TableSimpleColumnsExample 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; 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; } // tslint:disable-next-line: no-any trafficHasProblem(row: any): DtIndicatorThemePalette { if (row.traffic > 90000000) { return 'error'; } else if (row.traffic > 60000000) { return 'warning'; } } } <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" ></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" [hasProblem]="trafficHasProblem" ></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 TableSimpleColumnsExample 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; 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; } // tslint:disable-next-line: no-any trafficHasProblem(row: any): DtIndicatorThemePalette { if (row.traffic > 90000000) { return 'error'; } else if (row.traffic > 60000000) { return 'warning'; } } }

Sorting, paging and filtering out of the box with DtTableDataSource

dtSimpleColumns integrate out of the box with the DtTableDataSource. 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: `
    <dt-table [dataSource]="dataSource" dtSort #sortable>
      [... column and row definitions]
    </dt-table>
  `,
})
export class TableComponent implements AfterViewInit {
  // Get the viewChild to pass the sorter reference to the datasource.
  @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort;

  // Create the Datasource instanciate it.
  dataSource: DtTableDataSource<object>;
  constructor() {
    this.dataSource = new DtTableDataSource(this.data);
  }

  // Connect the `dtSort` instance to the DtTableDataSource
  ngAfterViewInit(): void {
    this.dataSource.sort = this.sortable;
  }
}

Pagination

´ Loading interactive demo...
<dt-table [dataSource]="dataSource" dtSort #sortable> <dt-simple-text-column name="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" ></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" [hasProblem]="trafficHasProblem" ></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; } // tslint:disable-next-line: no-any trafficHasProblem(row: any): DtIndicatorThemePalette { if (row.traffic > 90000000) { return 'error'; } else if (row.traffic > 60000000) { return 'warning'; } } } <dt-table [dataSource]="dataSource" dtSort #sortable> <dt-simple-text-column name="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" ></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" [hasProblem]="trafficHasProblem" ></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; } // tslint:disable-next-line: no-any trafficHasProblem(row: any): DtIndicatorThemePalette { if (row.traffic > 90000000) { return 'error'; } else if (row.traffic > 60000000) { return 'warning'; } } }

Further examples of the DtPagination in combination with a DtTableDataSource can be found under the pagination page.

Show more

´ Loading interactive demo...
<dt-table [dataSource]="dataSource"> <dt-simple-text-column name="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()"></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" 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()"></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, }); }

Filtering with highlight of the filtered value

´ 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"> <dt-highlight [term]="value">{{ 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">{{ 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> <input dtInput [dtAutocomplete]="auto" [(ngModel)]="value" (ngModelChange)="filter()" placeholder="Start typing" /> <dt-autocomplete #auto="dtAutocomplete"> <dt-option *ngFor="let option of filterableValues" [value]="option"> {{ option }} </dt-option> </dt-autocomplete> export class TableFilteringExample { private data: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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, }, ]; value: string; dataSource: DtTableDataSource<object>; get filterableValues(): string[] { return this.data.map( (data: { host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }) => data.host ); } constructor() { this.dataSource = new DtTableDataSource(this.data); } filter(): void { this.dataSource.filter = this.value; } } <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]="value">{{ 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">{{ 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> <input dtInput [dtAutocomplete]="auto" [(ngModel)]="value" (ngModelChange)="filter()" placeholder="Start typing" /> <dt-autocomplete #auto="dtAutocomplete"> <dt-option *ngFor="let option of filterableValues" [value]="option"> {{ option }} </dt-option> </dt-autocomplete> export class TableFilteringExample { private data: Array<{ host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }> = [ { 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, }, ]; value: string; dataSource: DtTableDataSource<object>; get filterableValues(): string[] { return this.data.map( (data: { host: string; cpu: number; memoryPerc: number; memoryTotal: number; traffic: number; }) => data.host ); } constructor() { this.dataSource = new DtTableDataSource(this.data); } filter(): void { this.dataSource.filter = this.value; } }

Extending DtSimpleColumn

Of course 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>