The table component can be a static or an interactive element. Some tables provide the possiblity to add, remove, edit a row or expand it for further information.

<dt-table [dataSource]="dataSource" dtSort #sortable>
  <dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
  <dt-simple-number-column
    name="cpu"
    label="CPU"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryPerc"
    label="Memory"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryConsumption"
    label="Memory combined"
    [displayAccessor]="combineMemory"
    [sortAccessor]="memorySortAccessor"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="traffic"
    label="Traffic"
    [formatter]="trafficFormatter"
    sortable="false"
  ></dt-simple-number-column>
  <dt-header-row
    *dtHeaderRowDef="[
        'host',
        'cpu',
        'memoryPerc',
        'memoryConsumption',
        'traffic'
      ]"
  ></dt-header-row>
  <dt-row
    *dtRowDef="
        let row;
        columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
      "
  ></dt-row>
</dt-table>

The DtTable implementation enhances the Material's CDK table and also removes unneeded properties from the public API. The CDK table has a very different approach on how to define the table template, it does not use the native HTML table. Therefore, there are no td, tr or th tags involved. Instead, you need to define all possible columns that the table may show (depending on the data available) and then define which subset of columns you want to show in the table header and body by selecting from the column definitions.

Imports

You have to import the DtTableModule to use the dt-table. If you want to use the dt-expandable-cell component, Angular's BrowserAnimationsModule is required for animations. For more details on this see Step 2: Animations in the getting started guide. If you want to use the dt-order-cell, Angular's DragDropModule is required for reordering table rows via drag and drop. For more details on this see the Order section.

import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DtTableModule } from '@dynatrace/barista-components/table';

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

Table inputs

The DtTable component supports the following inputs. Find details about the usage of each input below.

Name Type Default Description
dataSource object[] | Observable | DataSource Data to be shown in the table.
loading boolean false Whether the table is loading or not.
multiExpand boolean false Whether the table allows multiple rows to be expanded at a time.
exportButton boolean | 'table' | 'visible' false Whether the table includes an export button.

Simple columns for basic use cases

For the most common column types (text and number columns) the Angular components provide a DtSimpleColumn implementation that wraps the underlying, more complex table setup. The dtSimpleColumn is an abstraction layer to the full fledged table implementation to make usage of recurring-patterns easier and to reduce boiler plate code that needs to be written to generate a simple table.

A dtTable using a dtSimpleColumn always needs the dtSort directive.

<dt-table [dataSource]="dataSource" dtSort #sortable>
  <dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
  <dt-simple-number-column
    name="cpu"
    label="CPU"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryPerc"
    label="Memory"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryConsumption"
    label="Memory combined"
    [displayAccessor]="combineMemory"
    [sortAccessor]="memorySortAccessor"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="traffic"
    label="Traffic"
    [formatter]="trafficFormatter"
    sortable="false"
  ></dt-simple-number-column>
  <dt-header-row
    *dtHeaderRowDef="[
        'host',
        'cpu',
        'memoryPerc',
        'memoryConsumption',
        'traffic'
      ]"
  ></dt-header-row>
  <dt-row
    *dtRowDef="
        let row;
        columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
      "
  ></dt-row>
</dt-table>

DtSimpleColumn

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

Inputs

Name Type Default Description
name string - The name of the dtSimpleColumn refers to the name of the column which it uses to register itself at the table. This name can be used to reference the column in the dt-row. The name input is the only required input on the simple column.
label string - The label defines the string rendered into the header-cell of the given column. If no label is given, the name of the cell is being used. (Optional)
sortable boolean true The sortable input defines whether the column should be sortable.
displayAccessor<T> (data: T, name: string) => any - The displayAccessor function can be used to extract the displayable data from any row data. The name property passes the currently rendered column name, which can be used for more generic functions. If no displayAccessor is given, the dtSimpleColumn tries to extract a displayable data from rowData[name]. (Optional)
sortAccessor<T> (data: T, name: string) => string | number - The sortAccessor function can be used to extract sortable data from any row data. The name property passes the currently rendered column name, which can be used for more generic functions. This sortAccessor function will be used by the dataSource to access sortable values from the row data. (Optional)
formatter (displayValue: any) => string | DtFormattedValue - The formatter function can be used to fomat the displayed value, with either prepared DtFormatter functions or custom functions. Can be used on top of the displayAccessor function or standalone. The function gets passed either the output from the displayAccessor or the fallback data. (Optional)
hasProblem<T> (data: T, name: string) => DtIndicatorThemePalette - The hasProblem function can be used to evaluate if a cell should add the dtIndicator and if it should display error or warning. The function gets passed the row data and the name of the current column, which allows for more generic functions. The function needs to return either error or warning if a problem should be active. (Optional)
dtColumnProportion number - Exposes the dtColumnProportion of the dtCell directive for use with simple columns
comparator<T> (left: T, right: T, name: string) => number - The comparator function can be used to specify a custom comparator which is used to compare two rows. If this property is set, the sortAccessor for this column is ignored. This function must return < 0 if left is logically smaller than right, 0 if they are equivalent, otherwise > 0. (Optional)

Variants

Currently there are three predefined versions of the dtSimpleColumn exposed: dt-simple-number-column, dt-simple-text-column and dt-favorite-column. There are only small differences between the number and text column:

dt-simple-text-column
  • When sorting this column, the sort direction will start ascending, e.g. A -> Z
  • Column alignment is set to text -> left
dt-simple-number-column
  • When sorting this column, the sort direction will start descending, e.g. 100 -> 0
  • Column alignment is set to number -> right
  • When no formatter is given, the dtCount formatter will automatically be applied, e.g. 1000 -> 1k
dt-favorite-column
  • Column alignment is set to icon -> center
  • When sorting this column, the sort direction will start descending, e.g. ★ -> ☆

Default example of a favorite column:

<dt-table [dataSource]="dataSource" dtSort #sortable>
  <dt-favorite-column
    name="favorite"
    label="Favorite"
    (favoriteToggled)="toggleFavorite($event)"
  ></dt-favorite-column>
  <dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef dt-sort-header>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.memoryPerc }} / {{ row.memoryTotal }}
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['favorite', 'host', 'memory']"
  ></dt-header-row>
  <dt-row *dtRowDef="let row; columns: ['favorite', 'host', 'memory']"></dt-row>
</dt-table>

When no label is given, nothing will be rendered inside the header-cell:

<dt-table [dataSource]="dataSource">
  <dt-favorite-column
    name="favorite"
    sortable="false"
    (favoriteToggled)="toggleFavorite($event)"
  ></dt-favorite-column>
  <dt-simple-text-column
    name="host"
    label="Host"
    sortable="false"
  ></dt-simple-text-column>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.memoryPerc }} / {{ row.memoryTotal }}
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['favorite', 'host', 'memory']"
  ></dt-header-row>
  <dt-row *dtRowDef="let row; columns: ['favorite', 'host', 'memory']"></dt-row>
</dt-table>

Custom columns for advanced use cases

If the simple column implementation does not cover your use cases, you can use the underlying API to create your own column, cell, and header definitions as follows:

Each column definition is created with dt-header-cell and dt-cell inside an ng-container structural directive with a dtColumDef attribute directive applied to it.

<ng-container dtColumnDef="username">
  <dt-header-cell *dtHeaderCellDef>User name</dt-header-cell>
  <dt-cell *dtCellDef="let row"><span ngNonBindable>{{row.a}}</span></dt-cell>
</ng-container>

Note: dtCellDef not only exports the row data but also the same properties as *ngFor- using the same micro-syntax. The table header is defined with a dt-header-row component and a dtHeaderRowDef directive:

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

Finally the table row is defined with a dt-row component and a dtRowDef directive:

<dt-row *dtRowDef="let row; columns: ['username', 'age', 'title']"></dt-row>

Note: The dtRowDef also exports row context, which can be used for event and property bindings on the row element. See the source code of the examples on this page to see all the pieces in place.

<dt-table [dataSource]="data">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <dt-info-group>
        <dt-info-group-icon>
          <dt-icon name="host"></dt-icon>
        </dt-info-group-icon>
        <dt-info-group-title>{{ row.host }}</dt-info-group-title>
        Uptime: {{ row.uptime }}
      </dt-info-group>
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu | dtPercent }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ combineMemory(row) }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.traffic | dtMegabytes: 1024 | dtRate: 's' }}
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

Components and attributes that define a table

Name Type Description
dtColumnDef Attribute Name for the column (to be used in the header and row definitions).
dtColumnAlign Attribute Sets the column alignment. Find possible values below in the "Alignment in tables" section.
dt-header-cell Directive Adds the appropriate classes (the generic dt-header-cell and the cell specific dt-column-css_friendly_column_name) and role (so the browser knows how to parse it. In this case it makes it act as a column header in a native html table)
*dtHeaderCellDef Attribute Captures the template of a column's header cell (the title for the column in the header) as well as cell-specific properties so the table can render it's header properly.
dt-cell Component Adds the appropriate classes and role (so the browser knows how to parse it. In this case it makes it act as a grid cell in a native html table).
*dtCellDef Attribute Exports the row data and the same properties as an ngFor in a way you can define what the cell should show. It also captures the template of the column's data row cell.
dt-header-row Component Placeholder for the header row. It is a container that contains the cell outlet. Adds the appropriate class and role.
*dtHeaderRowDef Attribute Defines the visible columns in the header out of all defined ones by receiving a columnName[].
dt-row Component Placeholder for the data rows. It is a container for the cell outlet. Adds the right class and role.
*dtRowDef Attribute Defines the visible columns in each row by receiving a columnName[] and also exposes the same micro-syntax that the dt-cell but for event and property binding.

Alignment in tables

Content can be centered, left- or right-aligned depending on the data. Header text should always follow the same alignment as the column content.

  • Left-aligned content
    • Text
    • Identification numbers beginning with letters, e.g. ID
  • Right-aligned content
    • Numbers
    • Date, time, year,...
    • IP addresses
  • Center-aligned content
    • Icons
    • Interactive components (e.g. switches)

Add the dtColumnAlign attribute to the ng-container that wraps the column definition to define the column's text alignment. The attribute accepts the following values:

Attribute values Alignment
left left
text left
id left
right right
number right
date right
ip right
center center
icon center
control center

Data source

The data source contains the data to be shown in the table. It can be an array, an observable holding an array or a DataSource object.

The Angular components provide a DtTableDataSource that provides a lot of functionality (like filtering, sorting, pagination) already set up. The DtTableOrderDataSource provides functionality to reorder the table, but does not work in combination with filtering, sorting or pagination. For use cases that can not be implemented using the DtTableDataSource you can always create your own data source that implements the DataSource interface.

Sorting

The DtSort and dt-sort-header are used to add sorting functionality to the table. To add sorting capabilities to a table add the dtSort directive to the dt-table component.

<dt-table ... dtSort ...></dt-table>

For each column that should be sortable by the user add dt-sort-header to the dt-header-cell. The dt-sort-header registers itself with the ID given to the dtColumnDef with the DtSort directive.

<dt-header-cell dt-sort-header ...></dt-header-cell>
<dt-table
  [dataSource]="dataSource"
  dtSort
  (dtSortChange)="sortData($event)"
  [dtSortDisabled]="disableSorting"
  [dtSortActive]="'cpu'"
  dtSortStart="asc"
  dtSortDirection="desc"
>
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell
      *dtHeaderCellDef
      dt-sort-header
      sort-aria-label="Change sort order for hosts"
    >
      Host
    </dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell
      *dtHeaderCellDef
      dt-sort-header
      start="desc"
      sort-aria-label="Change sort order for CPUs"
    >
      CPU
    </dt-header-cell>
    <dt-cell *dtCellDef="let row"> {{ row.cpu | dtPercent }} </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell
      *dtHeaderCellDef
      dt-sort-header
      start="desc"
      sort-aria-label="Change sort order for memory"
    >
      Memory
    </dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.memoryPerc | dtPercent }} of {{ row.memoryTotal | dtBytes }}
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell
      *dtHeaderCellDef
      disabled
      dt-sort-header
      sort-aria-label="Change sort order for network traffic"
    >
      Network traffic
    </dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.traffic | dtBytes | dtRate: 's' }}
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="disableSorting = !disableSorting"
>
  Toggle disable sorting for all columns
</button>

DtSort

You can set the following inputs and outputs on the dtSort directive.

Inputs

Name Type Default Description
dtSortActive string The ID of the most recent active column.
dtSortDirection DtSortDirection asc The sort direction of the currently active colum, which can be used for initially sorting it.
dtSortDisabled boolean false Whether sorting is disabled for the entire table.
dtSortStart DtSortDirection Sort direction in which a column is initially sorted when the user interacts with it. May be overriden by the DtSortHeader's sort start.

Outputs

Name Type Default Description
sortChange EventEmitter<DtSortEvent> Event emmited when the user changes either the active sort or the sorting direction.

Methods

Name Description Parameters Return value
sort Sets the active sort ID and new sort direction sortable: DtSortHeader or active: string, direction: DtSortDirection void

DtSortHeader

You can set the following inputs and outputs on the dt-sort-header component.

Inputs

Name Type Default Description
disabled boolean Whether sorting is disabled for this sort header.
start DtSortDirection asc Overrides the sort start value of the containing DtSort.
sort-aria-label string Sets the aria label for the button used for sorting.

Accessibility

Please provide a sort-aria-label for each dt-sort-header to make the sorting experience accessible for all users. E.g. Change sort order for column hosts.

DtSortDirection

The type used for the sort direction, either asc or desc.

DtSortEvent

The event emitted when the user changes either the active sort or the sorting direction. The event contains the following properties.

Name Type Description
active string The ID of the currently active column.
direction DtSortDirection The direction for the currently active column.

Ordering

The DtOrder and dt-order-cell in combination with Angular's DragDropModule are used to add ordering functionality to the table. To add ordering capabilities to a table, import the DragDropModule and add the dtOrder and cdkDropList directive and cdkDropListData input to the dt-table component. When using the dt-order-cell, the data source provided for the table must be of type DtTableOrderDataSource. Tables using the dt-order-column can't be sorted or paginated.

<dt-table ... dtOrder cdkDropList [cdkDropListData]="dataSource" ...></dt-table>

The cdkDropListData gets the same data as the table's dataSource input. When combining the dt-order-cell with dt-simple-columns, their sortable input should be set to false. The DtTableOrderDataSource does not mutate the original data when ordering, if you want to persist the ordered state you have to take care of that yourself.

<dt-table
  [dataSource]="dataSource"
  dtOrder
  [dtOrderDisabled]="disableOrdering"
  cdkDropList
  [cdkDropListData]="dataSource"
>
  <ng-container dtColumnDef="order" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
    <dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
    </dt-order-cell>
  </ng-container>
  <dt-simple-text-column
    name="name"
    label="Rule name"
    sortable="false"
  ></dt-simple-text-column>
  <dt-header-row *dtHeaderRowDef="['order', 'name']"></dt-header-row>
  <dt-row *dtRowDef="let row; columns: ['order', 'name']"></dt-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="disableOrdering = !disableOrdering"
>
  Toggle disable ordering
</button>

DtOrder

You can set the following inputs and outputs on the dtOrder directive.

Inputs

Name Type Default Description
dtOrderDisabled boolean false Whether ordering is disabled for the entire table.

Outputs

Name Type Default Description
dtOrderChange EventEmitter<DtOrderChangeEvent> Event emmited when the user changes the order of the table, either by dragging a row to a new position or by changing the input value.

Methods

Name Description Parameters Return value
order Changes the position of a row based on the row's index currentIndex: number
targetIndex: number

Ordering with expandable rows

Ordering also works with custom columns and expandable rows.

<dt-table
  [dataSource]="dataSource"
  [multiExpand]="multiExpand"
  dtOrder
  cdkDropList
  [cdkDropListData]="dataSource"
>
  <ng-container [dtColumnDef]="'order'" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
    <dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
    </dt-order-cell>
  </ng-container>
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="details" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
    <dt-expandable-cell
      *dtCellDef
      ariaLabel="Expand the row"
    ></dt-expandable-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['order', 'details', 'host', 'memory', 'cpu', 'traffic']"
  ></dt-header-row>
  <dt-expandable-row
    *dtRowDef="
      let row;
      columns: ['order', 'details', 'host', 'memory', 'cpu', 'traffic']
    "
    [expanded]="row.expanded"
  >
    <ng-template dtExpandableRowContent>
      Expandable section for {{ row.host }}
    </ng-template>
  </dt-expandable-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="multiExpand = !multiExpand"
>
  Toggle multiexpand (current value: {{ multiExpand }})
</button>

Ordering with data from observable

<button
  *ngIf="!isSubscribed; else cancel"
  class="dt-example-button"
  dt-button
  (click)="startSubscription()"
>
  Start subscription
</button>
<button
  class="dt-example-button"
  dt-button
  variant="secondary"
  (click)="clearRows()"
>
  Clear
</button>
<dt-table
  [dataSource]="dataSource"
  dtOrder
  cdkDropList
  [cdkDropListData]="dataSource"
>
  <ng-container [dtColumnDef]="'order'" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Order</dt-header-cell>
    <dt-order-cell *dtCellDef="let data; let index = index" [index]="index">
    </dt-order-cell>
  </ng-container>
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="control">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['order', 'host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['order', 'host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
  <dt-empty-state role="row">
    <dt-empty-state-item role="cell">
      <dt-empty-state-item-img>
        <img
          alt="glass"
          src="data:image/png;base64,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"
        />
      </dt-empty-state-item-img>
      <dt-empty-state-item-title aria-level="1">
        No data that matches your query
      </dt-empty-state-item-title>
      To add data to the query, click the start subscription button.
    </dt-empty-state-item>
  </dt-empty-state>
</dt-table>
<ng-template #cancel>
  <button class="example-button" dt-button (click)="cancelSubscription()">
    Cancel subscription
  </button>
</ng-template>

DtOrderEvent

The event emitted when the user changes the order of the table, either by dragging a row to a new position or by changing the input value. The event contains the following properties.

Name Type Description
previousIndex number The index of the row prior to changing the order.
currentIndex number The index of the row after changing the order.

Searching/Filtering

When tables contain large amounts of data, make it easier for the user to find entries by providing a search field above the table. The DtTableSearch component can be used in combination with a table to provide this functionality.

Filtering data for the table means filtering out rows that are passed via the data source. For highlighting the matched strings in the table the DtHighlight component can be used.

<dt-table-search
  name="tableSearch"
  [(ngModel)]="searchValue"
  placeholder="Search table data..."
  aria-label="Search table data"
></dt-table-search>
<dt-table [dataSource]="dataSource">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <dt-highlight [term]="searchValue">{{ row.host }}</dt-highlight>
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ combineMemory(row) }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.traffic | dtMegabytes: 1024 | dtRate: 's' }}
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

DtTableSearch

Inputs

Name Type Default Description
value string '' The current search term.
placeholder string undefined Placeholder string for the input field (always needs to start with "Search ...").
aria-label string undefined An ARIA label describing the input field.
aria-labelledby string undefined A reference to an ARIA description of the input field.

Outputs

Name Type Description
valueChange EventEmitter<DtTableSearchChangeEvent> Event emitted when the user changes the search term.

Pagination and show more

The DtPagination component can be used in combination with a table to provide pagination for large datasets.

<dt-table [dataSource]="dataSource" dtSort #sortable>
  <dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
  <dt-simple-number-column name="cpu" label="CPU"></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryPerc"
    label="Memory"
    [formatter]="percentageFormatter"
    dtColumnProportion="3"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memoryConsumption"
    label="Memory combined"
    [displayAccessor]="combineMemory"
    [sortAccessor]="memorySortAccessor"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="traffic"
    label="Traffic"
    sortable="false"
    [formatter]="trafficFormatter"
  ></dt-simple-number-column>
  <dt-header-row
    *dtHeaderRowDef="[
        'host',
        'cpu',
        'memoryPerc',
        'memoryConsumption',
        'traffic'
      ]"
  ></dt-header-row>
  <dt-row
    *dtRowDef="
        let row;
        columns: ['host', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic']
      "
  ></dt-row>
</dt-table>
<dt-pagination></dt-pagination>

In some use cases we might not know how much data we have in total. In this case a DtShowMore componenent might be more suitable.

<dt-table [dataSource]="dataSource">
  <dt-simple-text-column
    name="host"
    label="Host"
    sortable="false"
  ></dt-simple-text-column>
  <dt-simple-number-column
    name="cpu"
    label="CPU"
    sortable="false"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="memory"
    label="Memory"
    sortable="false"
    [formatter]="percentageFormatter"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="traffic"
    label="Traffic"
    sortable="false"
    [formatter]="trafficFormatter"
  ></dt-simple-number-column>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>
<button dt-show-more (click)="loadMore()">Show 5 more</button>

Selectable table rows

The DtTableRowSelector can be used for selectable rows in a table and the DtTableHeaderSelector to provide bulk selection in the column header.

The DtTableSelection directive has to be added to the table to enable selection handling. The directive also provides access to the currently selected rows and allows you to change selection programmatically. It also supports a selection limit by providing a DtTableSelectionConfig via the DT_TABLE_SELECTION_CONFIG injection token.

Inputs

Name Type Default Description
dtTableSelectionInitial T[] [] The rows that should be selected initially.
dtTableIsRowDisabled Predicate<T> () => false Predicate to disable matching rows

Outputs

Name Type Description
dtTableSelectionChange Observable<SelectionChange<T>> Event emitted when the selection changes either by user interaction or programmatically.
<dt-table
  [dataSource]="dataSource"
  dtSort
  dtTableSelection
  [dtTableIsRowDisabled]="isDisabled"
>
  <ng-container dtColumnDef="checkbox">
    <dt-table-header-selector
      *dtHeaderCellDef
      aria-label="Toggle all hosts"
    ></dt-table-header-selector>
    <dt-table-row-selector
      *dtCellDef="let row"
      [row]="row"
      [aria-label]="'Toggle ' + row.host"
    ></dt-table-row-selector>
  </ng-container>
  <dt-simple-text-column name="host" label="Host"></dt-simple-text-column>
  <dt-simple-number-column name="cpu" label="CPU"></dt-simple-number-column>
  <dt-header-row *dtHeaderRowDef="['checkbox', 'host', 'cpu']"></dt-header-row>
  <dt-row *dtRowDef="let row; columns: ['checkbox', 'host', 'cpu']"></dt-row>
</dt-table>
Current selection: {{ getCurrentSelection() }}

Sorting, paging and filtering out of the box with DtTableDataSource

Merging the streams for sorting, filtering and pagination can get quite tricky. The DtTableDataSource has all this features already set up.

Unified sorting (locale-aware for strings, null/undefined value treatment) is possible when using the DtTableDataSource. To do this, create a new DtTableDataSource instance with the data. You will have to connect the input instances for dtSort to the DtTableDataSource.

@Component({
  template: `
    <input dtInput (input)="updateFilter($event)" />
    <dt-table [dataSource]="dataSource" dtSort #sortable>
      [... column and row definitions]
    </dt-table>
    <dt-pagination></dt-pagination>
  `,
})
export class TableComponent implements OnInit {
  // Get the viewChild to pass the sorter, pagination, and filter reference to the datasource.
  @ViewChild('sortable', { read: DtSort, static: true }) sortable: DtSort;
  @ViewChild(DtPagination, { static: true }) pagination: DtPagination;

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

  ngOnInit(): void {
    // Set the dtSort reference on the dataSource, so it can react to sorting.
    this.dataSource.sort = this.sortable;
    // Set the dtPagination reference on the dataSource, so it can page the data.
    this.dataSource.pagination = this.pagination;
    // Set the pageSize to override the default page size.
    this.dataSource.pageSize = 10;
  }

  updateFilter(event: InputEvent): void {
    this.dataSource.filter = event.srcElement.value;
  }
}

The DtTableDataSource exposes two functions, that let the user define sort accessors for named columns. This enables the user to leverage DtTableDataSource sorting without the use of dt-simple-columns. The function addSortAccessorFunction(columnName: string, fn: DtSortAccessorFunction) can be used to add a custom sortAccessor function to the data source. The custom added sort accessors takes precedence over the automatically added ones from dt-simple-columns.

The function removeSortAccessorFunction(columnName: string) enables the user to remove a previously defined sortAccessor function.

export class TableComponent implements OnInit, OnDestroy {
  //...
  // Create the Datasource instanciate it.
  dataSource: DtTableDataSource<object>;
  constructor() {
    this.dataSource = new DtTableDataSource(this.data);
    this.dataSource.addSortAccessorFunction('memory', (row) => {
      return (row.memoryPerc / 100) * row.memoryTotal;
    });
  }

  ngOnDestroy() {
    // Not necessary, but possible
    this.dataSource.removeSortAccessorFunction('memory');
  }
}

The DtTableDataSource also exposes two functions, that let the user define custom comparators for named columns. This enables the user to leverage DtTableDataSource comparing without the use of dt-simple-columns. The function addComparatorFunction(columnName: string, fn: DtColumnComparatorFunction) can be used to add a custom comparator function to the data source. The custom added comparator takes precedence over defined sortAccessor functions.

The function removeComparatorFunction(columnName: string) enables the user to remove a previously defined comparator function.

<dt-table [dataSource]="dataSource" dtSort #sortable>
  <dt-simple-text-column
    name="host"
    label="Host"
    [comparator]="compareStringLengths"
  ></dt-simple-text-column>
  <dt-simple-text-column
    name="namespace"
    label="Namespace"
  ></dt-simple-text-column>
  <dt-header-row *dtHeaderRowDef="['host', 'namespace']"></dt-header-row>
  <dt-row *dtRowDef="let row; columns: ['host', 'namespace']"></dt-row>
</dt-table>

Expandable table rows

To show more details in context of a single table row, use expandable rows. They can be defined using the dt-expandable-row component. An expandable row has to contain a column with a details cell. A details cell can be added using dt-expandable-cell. The content inside the dt-expandable-row needs to be wrapped inside a ng-template with the dtExpandableRowContent directive to lazy load the content when the row is expanded.

<dt-table [dataSource]="dataSource" [multiExpand]="multiExpand">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="control">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="details">
    <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
    <dt-expandable-cell
      *dtCellDef
      ariaLabel="Expand the row"
    ></dt-expandable-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['details', 'host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-expandable-row
    *dtRowDef="
        let row;
        columns: ['details', 'host', 'cpu', 'memory', 'traffic']
      "
    [expanded]="row.expanded"
  >
    <ng-template dtExpandableRowContent>
      Expandable section for {{ row.host }}
    </ng-template>
  </dt-expandable-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="multiExpand = !multiExpand"
>
  Toggle multiexpand (current value: {{ multiExpand }})
</button>
Component/Attribute Type Description
dt-expandable-row Component Placeholder for the expandable data rows. It is a container for the cell outlet and an expandable section. Adds the right class and role.
dt-expandable-cell Component Adds the appropriate classes, role and content for the details cell in an expandable table.
ng-template dtExpandableContent Directive Wraps the content of the expandable row for lazy loading

Use the table's multiExpand input to allow multiple rows to be expanded at a time. The expanded state of an expandable row can be set programmatically by using the row's expanded input.

DtExpandableRow

Inputs

Name Type Default Description
expanded boolean false Whether the row is expanded or not.

Outputs

Name Type Description
expandChange EventEmitter<DtExpandableRowChangeEvent> Event emitted when the row's expandable state changes.
expanded EventEmitter<DtExpandableRow> Event emitted when the row is expanded.
collapsed EventEmitter<DtExpandableRow> Event emitted when the row is collapsed.

DtExpandableCell

Expandable rows have to contain one column definition which contains a dt-expandable-cell. Its aria-label or aria-labelledby input describes the action of toggling the state of the expandable row. A sample column definition for the details column could look like this:

<ng-container dtColumnDef="details" dtColumnAlign="control">
  <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
  <dt-expandable-cell
    *dtCellDef
    ariaLabel="Expand the row"
  ></dt-expandable-cell>
</ng-container>

States

Empty state

When there is no data to display an empty state is shown. It can consist of some text that explains why there is no content and an illustration that helps to visualize the problem. Pass an empty state to the table using the <dt-empty-state> component or a custom empty state.

<dt-table [dataSource]="dataSource" dtSort [dtSortDisabled]="true">
  <dt-simple-text-column
    name="usersId"
    label="Users ID"
  ></dt-simple-text-column>
  <dt-simple-number-column
    name="sessionCount"
    label="Session count"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="averageDuration"
    label="Average duration"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="errors"
    label="Errors"
  ></dt-simple-number-column>
  <dt-simple-text-column name="country" label="Country"></dt-simple-text-column>
  <dt-simple-text-column name="city" label="City"></dt-simple-text-column>
  <dt-simple-text-column
    name="browserFamily"
    label="Browser family"
  ></dt-simple-text-column>
  <dt-simple-text-column name="device" label="Device"></dt-simple-text-column>
  <dt-empty-state role="row">
    <dt-empty-state-item role="cell">
      <dt-empty-state-item-img>
        <img
          alt="glass"
          src="data:image/png;base64,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"
        />
      </dt-empty-state-item-img>
      <!-- Give the empty state item an aria-level to indicate which level of heading it represents within the page -->
      <dt-empty-state-item-title aria-level="1">
        {{ emptyState.title }}
      </dt-empty-state-item-title>
      {{ emptyState.message }}
    </dt-empty-state-item>
  </dt-empty-state>
  <dt-header-row
    *dtHeaderRowDef="[
        'usersId',
        'sessionCount',
        'averageDuration',
        'errors',
        'country',
        'city',
        'browserFamily',
        'device'
      ]"
  ></dt-header-row>
  <dt-row
    *dtRowDef="
        let row;
        columns: [
          'usersId',
          'sessionCount',
          'averageDuration',
          'errors',
          'country',
          'city',
          'browserFamily',
          'device'
        ]
      "
  ></dt-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="toggleEmptyState()"
>
  Toggle empty state
</button>

Loading state

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

<dt-table [dataSource]="dataSource" [loading]="tableLoading">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-loading-distractor dtTableLoadingState>
    Loading...
  </dt-loading-distractor>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="tableLoading = !tableLoading"
>
  Toggle loading property
</button>

Problems: errors and warnings

If a table cell contains a problematic value, an indicator is used to highlight it with the error (red) status color. Warnings in tables indicate configuration issues using the warning (yellow) status color.

To get an error or warning indicator use the dtIndicator directive inside your dt-cell components on any HTML element or on your dt-cell component directly. The dt-row and dt-expandable-row will pick up if any dtIndicator was used inside the row's dt-cell and show the correct indicator. If one indicator has an error state set, the indicator on the row is an error indicator (i.e. error trumps warning). You can control the active state of the indicator by using the input named the same as dtIndicator.

<dt-cell [dtIndicator]="active" ...></dt-cell>

Single metric problem indication

If a single metric in a table entry is affected, only the affected value is highlighted.

Problem indication of entity or table row

If the problem affects the entity, but the affected metric is not in the table, the entity name is highlighted by the appropriate status color.

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

The example below shows both usages – a single metric inside a cell and the entire cell enhanced with the dtIndicator.

<dt-table [dataSource]="_dataSource">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.name }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell
      [dtIndicator]="metricHasProblem(row, 'cpuUsage')"
      [dtIndicatorColor]="metricIndicatorColor(row, 'cpuUsage')"
      *dtCellDef="let row"
    >
      {{ row.cpuUsage | dtPercent }}
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <span
        [dtIndicator]="metricHasProblem(row, 'memoryPerc')"
        [dtIndicatorColor]="metricIndicatorColor(row, 'memoryPerc')"
      >
        {{ row.memoryPerc | dtPercent }}
      </span>
      &nbsp;of&nbsp;
      <span
        [dtIndicator]="metricHasProblem(row, 'memoryTotal')"
        [dtIndicatorColor]="metricIndicatorColor(row, 'memoryTotal')"
      >
        {{ row.memoryTotal | dtBytes }}
      </span>
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.traffic | dtBits | dtRate: 's' }}
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="empty">
    <dt-cell *dtCellDef="let row">This is empty</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>
<button
  class="dt-toggle"
  dt-button
  variant="secondary"
  (click)="_toggleProblem()"
>
  Toggle problem
</button>

Advanced usage

To make the table header sticky, set the sticky input on the dtHeaderRowDef directive.

<dt-header-row
  *dtHeaderRowDef="['username', 'age', 'title']; sticky: true"
></dt-header-row>
<dt-table [dataSource]="dataSource">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']; sticky: true"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

Custom column width

The column width proportion can be customized using the dtColumnProportion attribute. It accepts a number input, e.g. [dtColumnProportion]="2" means that this column's width will be doubled compared to the regular ones.

<dt-table [dataSource]="dataSource">
  <ng-container dtColumnDef="host" dtColumnAlign="text" dtColumnProportion="3">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

The column's minimum width can be set using the dtColumnMinWidth attribute. It accepts a CSS string describing the minimum width for the column. [dtColumnMinWidth]="200" means that this column's width will be at least 200px.

<dt-table [dataSource]="dataSource">
  <ng-container
    dtColumnDef="host"
    dtColumnAlign="text"
    [dtColumnMinWidth]="300"
  >
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number" dtColumnMinWidth="50%">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

Dynamic columns

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

<dt-table [dataSource]="dataSource">
  <ng-container
    *ngFor="let column of columnsDef"
    [dtColumnDef]="column.id"
    [dtColumnAlign]="column.type"
  >
    <dt-header-cell *dtHeaderCellDef>{{ column.title }}</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row[column.id] }}</dt-cell>
  </ng-container>
  <dt-header-row *dtHeaderRowDef="columnsName"></dt-header-row>
  <dt-row *dtRowDef="let row; columns: columnsName"></dt-row>
</dt-table>

Interactive rows

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

<dt-table [dataSource]="dataSource" interactiveRows>
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
</dt-table>

Tables with two lines per row

If you want to have 2 lines of text and maybe an icon inside a row you can use the <dt-info-group> component. You can also take a look at the <dt-info-group> component's page for further information.

<dt-table [dataSource]="dataSource">
  <ng-container dtColumnDef="service">
    <dt-header-cell *dtHeaderCellDef>Service</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <dt-info-group>
        <dt-info-group-icon>
          <dt-icon name="services"></dt-icon>
        </dt-info-group-icon>
        <dt-info-group-title>{{ row.service }}</dt-info-group-title>
        {{ row.location }}
      </dt-info-group>
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="responseTime" dtColumnAlign="right">
    <dt-header-cell *dtHeaderCellDef>Response time</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      {{ row.responseTime | dtCount }} ms
    </dt-cell>
  </ng-container>
  <ng-container dtColumnDef="failureRate" dtColumnAlign="right">
    <dt-header-cell *dtHeaderCellDef>Failure rate</dt-header-cell>
    <dt-cell *dtCellDef="let row"> {{ row.failureRate | dtPercent }} </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['service', 'responseTime', 'failureRate']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['service', 'responseTime', 'failureRate']"
  ></dt-row>
</dt-table>

Responsive table

Since some tables might have a lot of data in them and screen space is very limited especially on devices with smaller screens you might want to switch between a table with expandable rows and normal rows. The example below shows a very simple approach how this might be done.

<dt-container-breakpoint-observer>
  <dt-table [dataSource]="dataSource">
    <ng-container dtColumnDef="host" dtColumnAlign="text">
      <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
      <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
    </ng-container>
    <ng-container dtColumnDef="cpu" dtColumnAlign="text">
      <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
      <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
    </ng-container>
    <ng-container dtColumnDef="memory" dtColumnAlign="number">
      <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
      <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
    </ng-container>
    <ng-container dtColumnDef="traffic" dtColumnAlign="control">
      <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
      <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
    </ng-container>
    <ng-container dtColumnDef="details" dtColumnAlign="text">
      <dt-header-cell *dtHeaderCellDef>Details</dt-header-cell>
      <dt-expandable-cell *dtCellDef></dt-expandable-cell>
    </ng-container>
    <dt-header-row *dtHeaderRowDef="_headerColumns"></dt-header-row>
    <dt-row
      *dtRowDef="
          let row;
          columns: ['host', 'cpu', 'memory', 'traffic'];
          let rowIndex = index;
          when: !_isTableNarrow
        "
    ></dt-row>
    <dt-expandable-row
      *dtRowDef="
          let row;
          columns: ['details', 'host', 'cpu'];
          let rowIndex = index;
          when: _isTableNarrow
        "
    >
      <ng-template dtExpandableRowContent>
        <dt-key-value-list>
          <dt-key-value-list-item>
            <dt-key-value-list-key>Memory</dt-key-value-list-key>
            <dt-key-value-list-value>{{ row.memory }}</dt-key-value-list-value>
          </dt-key-value-list-item>
          <dt-key-value-list-item>
            <dt-key-value-list-key>Traffic</dt-key-value-list-key>
            <dt-key-value-list-value>{{ row.traffic }}</dt-key-value-list-value>
          </dt-key-value-list-item>
        </dt-key-value-list>
      </ng-template>
    </dt-expandable-row>
  </dt-table>
</dt-container-breakpoint-observer>

Observable as data source

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

<button
  *ngIf="!isSubscribed; else cancel"
  class="dt-example-button"
  dt-button
  (click)="startSubscription()"
>
  Start subscription
</button>
<button
  class="dt-example-button"
  dt-button
  variant="secondary"
  (click)="clearRows()"
>
  Clear
</button>
<dt-table [dataSource]="dataSource">
  <ng-container dtColumnDef="host" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.host }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="cpu" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>CPU</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.cpu }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="memory" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef>Memory</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.memory }}</dt-cell>
  </ng-container>
  <ng-container dtColumnDef="traffic" dtColumnAlign="control">
    <dt-header-cell *dtHeaderCellDef>Network traffic</dt-header-cell>
    <dt-cell *dtCellDef="let row">{{ row.traffic }}</dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['host', 'cpu', 'memory', 'traffic']"
  ></dt-header-row>
  <dt-row
    *dtRowDef="let row; columns: ['host', 'cpu', 'memory', 'traffic']"
  ></dt-row>
  <dt-empty-state role="row">
    <dt-empty-state-item role="cell">
      <dt-empty-state-item-img>
        <img
          alt="glass"
          src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAYAAAA4qEECAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gQaCCky3/6ewQAAFo1JREFUeNrtXVtvY9d1/s6d5/B+EyWRFDWSRho547EDx4mTQZMmaDMFXKMGUsNtUyAtUKQokKc+9I/0IWj8kL64BdIUtgMM0hStkzix46RO7LEnc7FulERdeBfJQx6eex8Gew+PSEqkxLGdQAswxiIons3vrL3Wt7619hHjuq6LC3vkxl5AcAH0BdAXNr7xj/oCzWYTmqah1WrBsixYlgVZlqEoCmzbBsMwaDQaME0TADA7O4twOAxBEMAwzLmubds2bNuGKIofO9DMpJJht9sFz/PgeZ7+LAgC7t+/D13X4fP5EAqFYBgGarXa8C3Gskin05iamvK8XqvVYJomZFlGKBQaeV2macK2bViWBdd1oSgKOI7zvKfVakGSpEd6Q/qAdl3X40mu60LTNPh8PrBsf6QxDAOdTgc8z6PRaCAUCoFlWTiOg3K5DJ7noSgK4vE4arUaKpUKVFUduqD5+XnE4/Gh14lEIieCqqoqotGo57VisYh6vQ7DMMAwDFZXV+l30XUdfr8fLMtCVVU4jgNFUajDMAwDy7Jg2zYEQRiIwdhA1+t1FItFLC8vQ9d17O3todVqwXEciKKI2dlZDwidTgeVSgXVahWhUAjJZBLtdhuSJKHT6cC2bciyjGQy6bl59+7dQ7vd7l8Mw2BlZQV+v3/sL+I4DnZ3dzE3NweGYajD5PN5VKtVzzWIAxFTFAWCIKDdbsOyLPo+juMgyzJM00S32wXHcUilUkilUmMD7gG61WpBEAQUi0W0221omkbfKAgCAIDjOJimCVEUEQ6H6e85joNcLodOpwNFUXB4eAhd16FpGoLBIJaWlsCyLFzXxZ07d9DtdvtCxuzsLFKp1Jk8xjAMHB0dYWpqCrZt4/bt2wgGg2i1WnBdF7ZtTywMKIqCbDaLQCBwtmToui729vbQ6XRgGAZ93efzwTAMOI5Dk5amadA0DYqiwDRNRKNRNJtN1Go1RKNRSJKExcVFbG5uotlswjRNSJJEk9NxoBVF8Wz5YdZqtVCpVGCaJgKBAGKxGERRhCAIkGUZ5XIZlUoFsiyj3W6D4zjouj4RgEkM73Q6aLfbZwPacRysr69Tr/X5fNB1HZIk9YHSa51OBwBQKpUAgG616elpHB4e4ujoCPF4HN1uF5IkoVAooNlsUi+Ox+OYmZkBz/OwLItec5AdHh5if38fPM+DYRhomoZutwtFUVCr1Tw7sHf7T4QHsyzC4TAymQz29/eRTCbHp3eu66Lb7SKVSiGRSFBqVSwWcXBwMNIHRaNRChjHcdA0DYFAAIFAAPF4nN59kmQCgQCWl5dpzHQcB4VCAY7jYGFhoY/adbtdlEolMAyD2dlZ7OzsQBRFsCyLYrFIY+vxHTro9XEtEolgbm6Ohs92u42DgwOk0+nxYrRpmuA4ri/Au66L27dve8LIIEsmk5ibm6M/V6tV5PN5LCwsIBwOez63Wq1ib28Pq6urdOGn2dHREba3t+G6LtLpNJrNJo6OjmjSe9QWj8cxPz/vuelra2vIZDIjhTtaGQ6iLY7jQNO0kZIIx3GeL7y3twcAaDQayOfzfYu+evXqSCA7jkP/JfFR13XMz88jmUxOLCyMUnQVCgWUy2U4jgOfz4fV1dWxYj9/UkxSVXUkoAnDyGQyNFER75VluY+bj0KNSDU5NTWFWCwGSZJQKpUQjUahaRp0XUcwGESz2TxxjYTHk6LFMIyRdgHLsggEAjBNE5qmoVgsAgAsy8LU1BR4nsf09PRktI56vT7yB7VaLbRarb6Yrmka9vf3x/IgArKmaXAcB47jQFVVyLKMRqOBg4MD6LqOer0OWZaHx0WGgSRJaDabNKGT4oTceFEUIYoi/H4/AoEAJEkCwzDw+/0wDAOapkGWZfp6vV4fC5dTPdpxHHAcR2M34aKu64LjOFoxEbMsC9vb2/RnWZbBcRwkSUIsFhtbo/D5fDg4OICiKLQwIizCsiwa7izLQjgchqZpMAwDHMchEAjQtZH8QnQPXdehKApYlgXP89B1HYIgoNVq0TDo9/uhqipEUaSJneM4upZAIADDMMYq2YdqHYVCgW6Xk7YXwzBwHIduR4ZhIMsyAoEAstks9vf3YRiGJ5mMYq7rotPpoFgsQtM0mKYJlmXpfwRIomGIokjf07uek/IK+Z1hzITjuL7vxrIsrly5AoZhUK1WMTs7e3aPbrVap4Lcm6yIxxNaSECybRuzs7P0fWOVrAxDwwOhg7que26s67qIRCKUS1erVdi2jampKfh8Puzu7kIQhIGsSRAEyrsFQeijgscdiNz8mZkZ+Hw+uK5LK+MzA10oFMYChHBjwzCQzWYRi8U8xcK4uoBlWXS7Es8i2z0ajdLiyLIsxONxGqZIDO/1yF6Z1DAMCILQd+NJ8iYhkThR7/tCoRCVeXvFpmazOZKayA/yUlLtjbrFSWxcXl5GMBg8N51qt9vI5/OwLAuhUAiXLl2iX7JarSKdTtOY3e12Ua1WaTVLkl4sFsP09DQODg6oZ0qSRG/eIK37JPZCiq7Dw0OoqopAIACe57G/vz8S0H2udlZd4PLlyxMBmayB7IJ0Og2e5+E4Dvx+P8LhMBRFAcMwyGazKBQKqNfrqFQqKBQKNOZ2Oh0Eg0FPUUMEMRLaxrGtrS0wDINMJoNGo0HZlCiKI9HFgXr05uYmjo6ORl5ELBbDpUuXJlYgmKaJUqkEWZYpaK7rIpFIUIGeNBZarRZ0XYfruiiXyzQZGoZBWQJhGARkURTBMAxM0xwrf4RCISwuLoJlWTSbTbAsC7/fP1IniB8Uc4ku0W63Ydv20MUwDIO5uTkkEomJVmKu61K+SnYYCQ1kbQQs0gjodDoolUowTZPmB+K1ZP2EmpqmSbtBp8kLxyvESqWCqakpuntHbbfxw2gbWRDLshAEAbZtU8EpEAhA0zTU6/WJg0xK+OM81XVdVCoVlMtl5HI5HBwcgOM4BINByhgYhqGhglDPXibRy50dx6E9y95GwKDGwPGW2tTU1Nj9TP6ksrVarVJvyGQyHmnQ5/ONHedGMVVVoapqn45MEpppmlTOFUWRSq7BYJAWJaTQymQy2NraouU3oYy9LIj8P/nXcRywLDt0JxOGNZHKkCy6VCrRu+/z+fouOE6tP2qDN5/P00JhkMmyjGAwCEVR4PP5IAhCX/VqGAa9SVevXkWz2YSqqpQhtdtt+vmEadi2DUmS4DgODT2D1hCPx1Gv10dW7U71aJ7nEQ6HUSqVIAgCjUlEICL9NRIrJ2GlUsnTDCYJS5ZlxONxxGKxE1U/UrkJguDpO4bDYYTDYUrtKpWKRy7o9e5EIkHXQbyXZVlIkoS5uTn4fL4zFWD8aZoDKQzItlxfX8fq6ir8fj/1+mg0SrfrWc1xHDSbTRpTHceBJElYWFjwtIzaNQPljRYqeRWtUhdqzYDZtWEbDjieAe/j4I9KCE5JiM8FkFwMIJTy9XmlIAg0BBEwFxYWKBcn2gfLsshkMjRcktdIiDq31kGALhQKqFarEEURtm3Tyq83mzcaDQiCQKu3s9qtW7eoYJTL5WiJa+k2tn5Vxfava6jttsf+3FBKxtyno1j8fAJS4OGOWFtbozF+bm6O5iDTNHH37l0qrAWDQWQyGerhruvSjvtEgO4tIHRdp9pBMBjEzMzMROOzbdu4e/cu/H4/stnsgx6i4eDejw+x9rMSTO38XWxOYHHpcwl86qszkPw8bZ8ZhoGlpaU+Lr+xsQFN0yCKIqLRqEdAKhaLSCQSI3v1WJNKlmXh8PAQpml6ChSSqc9jveMCALB3u4F3X9lB58jApE1UeFx7No2FZxJU/x6ka1cqFTov4vf7ceXKlT6pYtRdPPZIGJn8SafTYBgGu7u7VKwJBAKQZflEMf7UWG25eO8HBay/WTrxfYGED/GcgkDCBynAgxNY2KYDXbWgVrqo7XTQKndP/IzM4xE8/WIOgswP1Vz8fj/29/chy3If0zg+BjdRoMkCNE3D0dERLUVJ4pRlmSaVsUvvro03v7uB0nprCLgSFp5JYu7JKJTo6aJ7p25g5706Nt8uQ60M1nDC0zK++M0lyGFx4C7TdR2BQGAgs2q32yiXyyNp7ecactza2kKtVvNUkpIkUWoYj8dH7kKYXRs/+faHqBf6iyAlIuLas2lkn4yCYcenkq7jYve9Ot6/uTcwFClREV/51gqUiOjJGZ1OB6qqIhKJ0F1q2zby+TzS6TR8Ph9M0xyp0XxmoF3Xxf379+kMHc/zVEAnMVuSpL4kMyxcvPHS2kBPXngmgSf/LAtePP8ot2U4uPWDXWz8ojKAmfjwlW+tQFQehgHS/+Q4DlNTU1Rw63a7nkHJ483nsZuzJ1m1WqWCjKIoVC7sdrv033a7PZLs+t4PCn0gsxyDz/7FPD7zQm4iIAMAL7J46s9z+OxfXgLLeYFpFrv41b/ngR63m56eRrVapR67vb2NTqdDZwpbrRbtko+tR49qR0dHnvZVp9Ohontvx2JzcxP5fH6oSrZ3+6gv8bEcgy/8zSLmn47jUdj8Z2K4/rdLfWDv32lg7eclT6WZSqVwcHAAy7IgSRIMw6DtMzLKqygKisUims0mGo3GwAbCmSf+GYbxqF/D+DeRMMmMx+LiIp2tswwH776y2/d7T784j9nHwniUNrMawtMvzuOX/7blef2DH+4h/XiExutEIoFqtQpN05BKpRCPx2HbtkcvMQwDoVAIe3t7aDQatPM/OztLw8qZPZoMxkiSNHDWeZBpmoZ79+7Rn+/9+LAvOS1dTyL3VAwfheWeimHpuvdkgaU7+O2P9j0OtbKygmazSRkWoXqkQhZFEbIsY2lpiVaXBwcHHjHrzB49MzODSqUCy7LoJCjpbpxkROyxdBtrP/OGDH9MwhPPZU699jvvvIO9vT1UKhUaM1mWhc/no3Nyjz/+OBRFOfWznngujYN7DbSrD3NJ/p0aHvujGfjjEgU7nU6j3W6j2+3SiVmiafdS2UgkAsMwkMlkoKoqrSbPFTpmZmaws7MDlmVpMjwJaLJgANj6VbWvrH7iuQw44fRN9vrrrw8UpYiWvb29jbfffhvPPvvsqayHE1g8+VwGb/7rhocObvyijGt/mhnoJERYchyHJkoSIkKhEPx+f9/Q6LnSOem4EHCHTaX2LpTw0e1f1/qEn8zjkYmFBV3X8dprr514MIlY+moE4WlvNZt/p4aTiC/RrG3bRqVSwa1btygdJOMQvd3xcx1/YxgGV65cwe7uLj0AROYoBrEMIsC0a0afCrd0PQmMWIukUinkcjmkUimEw2GIooh2u407d+7ggw8+8BQdt27dwpe//OVTvgiweD2J3/znzsPyumWimleRuBQ4keKSGRjbtmnDpFqt9p1zOfc5Q1EUsbi4iPX1dTQaDbqlBs0uE28ub3g5M8MC2SdG9+ZvfOMbA3dXLpdDu93G5uamB4xRLHstindf2YXrPFxzca01FOhyuUwH54ltbm4iEonQiaqJ8OjjRkpvQRCopny8e0FEmUree/wtMqN4dOLz2PHjcaMOu0sBHpFZb/Ksbvcf06vX69ja2uoDmYTOcrlMqe9EePQgVY/neXS7Xdp9JjEskUggm83SrdQqeVW1WM4/kTVomob79+97FbpMZuTfj+cU1AsPQ1qr6K1q9/b2cHh4OJI8Ua/XPc3siXp074V6e26xWMwTr9SqN34Hk75zX98wDLz66qseTh8Oh3Ht2rWRP+P4OjoN3RNKxpmLPl5b8JMEujcBko4z4bfHlbpe8wXPFzZUVcX3v/99mu1Jxn/hhRdGDh0PwodwTPV7UMAIMke7TKPa8ZNsEwOaSKUkbpFhlunp6b4va5tOH5c9T8j63ve+h0rloSI3OzuL559/fqxzgER0Om62+QDocTvfx3PFxIA+flbcdV164LKP5vEMLMMdCvw49v7773tAnp+fx9e+9rUzdeQHrYPlH7AH0hUn9YDf74dlWQN5uiiKfecQJwY0icueD+f5gYczeR8Hy3j4pYz22c8C9lI5ALhx48aZxx70Y+tgGYCXOLpzcrkcRFGkhYhpmtB13ROPOY7DwsJC3xomGqN7hwaj0Siy2ezgCjEqods0H2b3SvfM1+31tGAwONYUfl+sP7YOKShQKXXQ4U1BEBCJRDzNj5WVlYFtvIkBzfM8ZFlGp9OBKIrIZrNDE1FwSvJw1LPMahB75plnaOI5S5+y146v4/jgzbAcwXEcnUUZtAbDMCb7BJpwOAxVVekJgKF8dS6A/P89rNjqux2YXRuCb/wtf+XKFXqAdNSDOwMB023Udr39ymj2dH6fyWTo0exh1ul0Jgs0acSSEDLMw5KLXjbg2C72bh9h/jPjdVRs28bLL79Mi4hUKoWvf/3rZ5r43P+gAcfy5pjU5dOPTBweHiIUCg28puu6qNVqDyTkSQLt9/shSRKdqx5moZQPoZRXLdt4qzL29XZ2djyVWrFYHDi8OIpt/MKrjQs+DomF0z16enp64INcjo6OUKlUEAgEHghMmLBNT09DUZRTz3XMfTrapyuU1tWx88Ior51m5Q0Vlbw3PmefjILjR5hAOiYe1et17O7uQpIkJJNJyromDnQwGMT8/Dyq1eqJj3BY/Hyir1B57zWvejZKfFxdXaU/r6ysjDV4+KD6c/Hea7t9sunSF5Jn3tXZbLZvWov5OB+Z+ZtXdrH+c++Wvfons3jsj8cboCQnD0ZpXR23u/9ziA9+uOd5bWY1jD/4u6WJfteP9QGDn/rqjGdgBQB++98HKK21xvocRVHOBHJpXcXtH3kfCMCwDK49m574d2U+7ofAbr5dwTv/sd2XiP7wH5YRzSiP7Lr1Qgc/+faHfQJXO7mNllKALMu4cePG2KHoE+nRwIORr+O9QjKHV95QH8k1y+vqQJCrobsos+vodruo1+u4efPm70foIPb0i7m+5qjZtfHTf/kQ939S9IxpnU+PAe69foiffmcwyC3ZG0Z6h2R+50MHMa1h4H//+T469f6mbjyn4NPPzyE2d/ZOTHVbxbuvFlDb6S/3B4EMACEzgxf++nnEc8rvD9DAg3nmN76zhmZpsMiUWg5h6QtJzKyGqXx5YuVoOji428T6W6WhCXYYyIqeRLJxFaIk4IvfXD432Mwn7YnoRsfCL1/ewsG95tD3CD4OiXk/YnN+BJI+SH7vxH+r3EVtp41KXoWlD9/6p4HMuCy93nnBZj6Jj553XWDtjRJu/9eeR7eeGNViGajxPMrs+qkg997c84D9iXxQN8MAy1+awo1/egy5p2JgJrjK6ZUQvvqPq2gphZFBJsn5je98iOp25/fHo49bq9zFxltl5H9dO1M3hpdYZK9FsXQ9SaXPl156ydPVPgnkSXg287v0Vytcx0V5Q0VxvYlqvo1mqYtuy+yjf6KfRzjlQzSjIHU5hKmlILhjjdft7W3cvHnzwaM9uzOI1C+fCvJ5wGZ+1/88iG05MDUbtumA5VmIMjdWV91xHNR3u3hjALeeJNjMxd9hITy780jBvvirFT1F0Re/uTxWO22cBHkB9EcE9gXQHxHYF0BPGOxhoxMXQE8Y7De/uzkwoV4APWGwtYaBrV9WL4D+KMAubzYvgP4owLZN9wLojwLsSFq5APpRg80JLBY/n7gAehJgf+nvLw88DsLyDD73V5fgj0kXWsekTG9bWPtZCeXNFlzbRTTrx9L15NCDTxdAf0R2ETougL4A+sIugP7k2v8Do6Jp3UCqD5oAAAAASUVORK5CYII="
        />
      </dt-empty-state-item-img>
      <dt-empty-state-item-title aria-level="1">
        No data that matches your query
      </dt-empty-state-item-title>
      To add data to the query, click the start subscription button.
    </dt-empty-state-item>
  </dt-empty-state>
</dt-table>
<ng-template #cancel>
  <button class="example-button" dt-button (click)="cancelSubscription()">
    Cancel subscription
  </button>
</ng-template>

Extending DtSimpleColumn

You can extend from the simpleColumn to create your own predefined simplecolumn. To do this, simply extend from the DtSimpleColumnBase<T> abstract class and implement the deviation that suits your needs. A basic template for the simpleColumn could look like this (example from the dt-simple-number-column).

<ng-container [dtColumnDef]="name" dtColumnAlign="number">
  <ng-container *dtHeaderCellDef>
    <dt-header-cell *ngIf="!sortable">{{ label || name }}</dt-header-cell>
    <dt-header-cell *ngIf="sortable" dt-sort-header start="desc">
      {{ label || name }}
    </dt-header-cell>
  </ng-container>
  <dt-cell
    *dtCellDef="let data"
    [dtIndicator]="_getIndicator(data, name)"
    [dtIndicatorColor]="_getIndicator(data, name)"
  >
    {{ _getData(data) }}
  </dt-cell>
</ng-container>

Exporting

Simple

By setting the showExportButton input to true, an dtContextDialog button is added just below the table, or in line with pagination if present. Alternatively, you may set it to visible or table to only show those buttons. Developers should prefer true over the alternatives as it gives the user the most value; however, limiting the output may be desirable if there are, for example, many columns in the table data which should not be exported. This dialog can contain up to 2 buttons:

  • Export table data which triggers a download of the currently filtered data as shown, without regard for pagination.
  • Export visible data which triggers a download of the filtered data from the datasource and does not use a displayAccessor.

To exclude certain columns from export, set exportExcludeList to a string array of column names to exclude.

<dt-table
  [dataSource]="dataSource"
  dtSort
  #sortable
  [showExportButton]="true"
  [exportExcludeList]="['action']"
  [loading]="tableLoading"
>
  <ng-container dtColumnDef="host" dtColumnAlign="text" dtColumnProportion="3">
    <dt-header-cell *dtHeaderCellDef>Host</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <dt-info-group>
        <dt-info-group-icon>
          <dt-icon name="host"></dt-icon>
        </dt-info-group-icon>
        <dt-info-group-title>{{ row.host }}</dt-info-group-title>
        Uptime: {{ row.uptime }}
      </dt-info-group>
    </dt-cell>
  </ng-container>
  <ng-container
    dtColumnDef="techType"
    dtColumnAlign="text"
    dtColumnProportion="1"
  >
    <dt-header-cell start="asc" *dtHeaderCellDef dt-sort-header i18n
      >Technology
    </dt-header-cell>
    <dt-cell *dtCellDef="let row"> {{techType(row)}} </dt-cell>
  </ng-container>
  <dt-simple-number-column name="cpu" label="CPU" dtColumnProportion="1">
  </dt-simple-number-column>
  <dt-simple-number-column
    name="memoryPerc"
    label="Memory"
    [formatter]="percentageFormatter"
    dtColumnProportion="1"
  >
  </dt-simple-number-column>
  <dt-simple-number-column
    name="memoryConsumption"
    label="Memory combined"
    [displayAccessor]="combineMemory"
    [sortAccessor]="memorySortAccessor"
    dtColumnProportion="2"
  ></dt-simple-number-column>
  <dt-simple-number-column
    name="traffic"
    label="Traffic"
    sortable="false"
    [formatter]="trafficFormatter"
    dtColumnProportion="2"
  >
  </dt-simple-number-column>
  <ng-container dtColumnDef="action" dtColumnAlign="text">
    <dt-header-cell *dtHeaderCellDef>Action</dt-header-cell>
    <dt-cell *dtCellDef="let row">
      <a href="/filter" dt-icon-button>
        <dt-icon variant="secondary" name="filter"></dt-icon>
      </a>
      <dt-context-dialog
        aria-label="Show more details"
        ariaLabelClose="Close context dialog"
      >
        <p>Drilldowns go here</p>
      </dt-context-dialog>
    </dt-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="[
        'host',
        'techType',
        'cpu',
        'memoryPerc',
        'memoryConsumption',
        'traffic',
        'action'
      ]"
  ></dt-header-row>
  <dt-row
    *dtRowDef="
        let row;
        columns: ['host', 'techType', 'cpu', 'memoryPerc', 'memoryConsumption', 'traffic', 'action']
      "
  ></dt-row>
</dt-table>
<dt-pagination></dt-pagination>

Selection

If dtTableSelection is enabled and you have connected dtTableSelection to dtTableDataSource (similar to dtSort), you also will have a third button:

  • Export selected rows which triggers a download of the display data, but just for selected rows.

Note: in this example showExportButton is set to visible to demonstrate the suppression of the Export table data button.

<dt-table
  [dataSource]="dataSource"
  dtSort
  dtTableSelection
  showExportButton="visible"
  [dtTableIsRowDisabled]="isDisabled"
  exportExcludeList="'details','checkbox'"
>
  <ng-container dtColumnDef="checkbox" dtColumnProportion="1">
    <dt-table-header-selector
      *dtHeaderCellDef
      aria-label="Toggle all hosts"
    ></dt-table-header-selector>
    <dt-table-row-selector
      *dtCellDef="let row"
      [row]="row"
      [aria-label]="'Toggle ' + row.host"
    ></dt-table-row-selector>
  </ng-container>
  <dt-simple-text-column
    name="host"
    label="Host"
    dtColumnProportion="2"
  ></dt-simple-text-column>
  <dt-simple-number-column
    name="cpu"
    label="CPU"
    dtColumnProportion="1"
  ></dt-simple-number-column>
  <ng-container dtColumnDef="details" dtColumnAlign="number">
    <dt-header-cell *dtHeaderCellDef dtColumnProportion="1"
      >Details</dt-header-cell
    >
    <dt-expandable-cell
      *dtCellDef
      ariaLabel="Expand the row"
    ></dt-expandable-cell>
  </ng-container>
  <dt-header-row
    *dtHeaderRowDef="['checkbox', 'details', 'host', 'cpu']"
  ></dt-header-row>
  <dt-expandable-row
    *dtRowDef="let row; columns: ['checkbox', 'details', 'host', 'cpu']"
  >
    <ng-template dtExpandableRowContent>
      Expandable section for {{ row.host }}
    </ng-template>
  </dt-expandable-row>
</dt-table>
Current selection: {{ getCurrentSelection() }}