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

Hover on table row

Hover on table row

border-width: 1px //inside
border-color: $gray-500
Hover on table header

Hover on table header

font-family: Bernina Sans Regular
font-color: $gray-900

Selected

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

Variants

Tables with two lines per row

Table with two lines
x: 60px

Table entry link

font-family: Bernina Sans Regular
font-size: 14px
color: $turquoise-600

Second row

font-family: Bernina Sans Regular
font-size: 12px
color: $gray-700

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!

Expandable tables on entity screens

Expandable table on an entity screen
x: 2px, theme color shade 500
y: 16px
z: 12px
expanded table row: theme color shade 100

Expandable tables on settings pages

Expandable table on settings pages
x: 2px, $gray-700
y: 16px
expanded table row: $gray-200

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 TableEmptyStateComponent { 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 TableEmptyStateComponent { 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 a metric

Problem indication of entity or table row

If the problem affects the entity, but the affected metric is not in the table, the entity name is highlighted in red.

Problem indication of a entity

Important note! Don't color hyperlinks even if the whole entity is affected, in this case use the red indicator.

Problem indication of a entity containing a link

Warning indication

Warnings in tables indicate configuration issues.

Warnings in tables
x: 2px

Warning text

font-family: Bernina Sans Regular
font-size: 12px
font-color: $gray-700

Warning icon

Incident icon
color: $warning
icon-width: 16px
icon-height: 16px

Behavior

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

Example workflow:

Create a table entry

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.

Table filter

Icon

width: 16px
height: 16px
color: $turquoise-600

Font

font family: Bernina Sans Regular
font size: 14px
color: $gray-500

Hover of filter button

Table filter hover
icon color: $turquoise-700
font color: $gray-600

Table filter behavior

As soon as filter is focused, an input field appears. The matching text is highlighted in the table entries. Table filter behavior

Table filter styling

Table filter styling
x: 16px
y: 4px
z: 8px

Input field

See input fields page

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. Responsive tables

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.

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

Description

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
isLoading boolean false DEPRECATED - will be removed with 3.0.0 Use loading instead.
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>

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

<dt-header-row *dtHeaderRowDef="['username', 'age', 'title']; sticky"><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.

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 TableDifferentWidthComponent { 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 TableDifferentWidthComponent { 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 TableWithInfoGroupCellComponent { 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 TableWithInfoGroupCellComponent { 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 TableMinWidthComponent { 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 TableMinWidthComponent { 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 TableEmptyStateComponent { 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 TableEmptyStateComponent { 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 TableEmptyCustomStateComponent { 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 TableEmptyCustomStateComponent { 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 TableLoadingComponent { 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 TableLoadingComponent { 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 TableObservableComponent { 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 TableObservableComponent { 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 TableDynamicColumnsComponent { 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 TableDynamicColumnsComponent { 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 TableExpandableRowsComponent { 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 TableExpandableRowsComponent { 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 TableMultiExpandableRowsComponent { 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 TableMultiExpandableRowsComponent { 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
multiple boolean false DEPRECATED - will be removed with 3.0.0 Use multiExpand input of table instead. Sets the mode for expanding multiple rows at a time.
expanded boolean false Whether the row is expanded or not.

Outputs

Name Type Description
openedChange EventEmitter<DtExpandableRow> DEPRECATED - will be removed with 3.0.0, use expandChange instead Event emitted when the expanded state changes.
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.

Properties

Name Type Description
contentViewContainer ViewContainerRef DEPRECATED - will be removed with 3.0.0 Gets a reference to the expandable container for dynamically adding components.

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 TableStickyHeaderComponent { 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 TableStickyHeaderComponent { 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 TableHoverComponent { 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 TableHoverComponent { 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 TableSortingComponent { 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 TableSortingComponent { 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 ...>

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

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

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 TableSortingFullComponent { 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 TableSortingFullComponent { 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" ...>

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 TableProblemComponent { _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 TableProblemComponent { _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 TableExpandableProblemComponent { _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 TableExpandableProblemComponent { _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 TableResponsiveComponent { 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 TableResponsiveComponent { 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"></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 TableSimpleColumnsComponent 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 }) 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"></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 TableSimpleColumnsComponent 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 }) 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 }) 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;
  }
}

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>