### File

`src/table/table.component.ts`

### Description

Build your table with this component by extending things that differ from default.

See demo

Instead of the usual write-your-own-html approach you had with `<table>`, carbon table uses model-view-controller approach.

Here, you create a view (with built-in controller) and provide it a model. Changes you make to the model are reflected in the view. Provide same model you use in the table to the `<ibm-pagination>` components. They provide a different view over the same data.

## Basic usage

     * <ibm-table [model]="model"></ibm-table>
     *

     * public model = new TableModel();
     *
     * this.model.data = [
     *     [new TableItem({data: "asdf"}), new TableItem({data: "qwer"})],
     *     [new TableItem({data: "csdf"}), new TableItem({data: "zwer"})],
     *     [new TableItem({data: "bsdf"}), new TableItem({data: "swer"})],
     *     [new TableItem({data: "csdf"}), new TableItem({data: "twer"})]
     * ];
     *

## Customization

If you have custom data in your table, you need a way to display it. You can do that by providing a template to `TableItem`.

     * <ng-template #customTableItemTemplate let-data="data">
     *     <a [routerLink]="data.link">{{data.name}} {{data.surname}}</a>
     * </ng-template>
     *

     * customTableItemTemplate: TemplateRef<any>;
     *
     * this.customModel.data = [
     *     [new TableItem({data: "asdf"}), new TableItem({data: {name: "Lessy", link: "/table"}, template: this.customTableItemTemplate})],
     *     [new TableItem({data: "csdf"}), new TableItem({data: "swer"})],
     *     [new TableItem({data: "bsdf"}), new TableItem({data: {name: "Alice", surname: "Bob"}, template: this.customTableItemTemplate})],
     *     [new TableItem({data: "csdf"}), new TableItem({data: "twer"})],
     * ];
     *

### Sorting and filtering

In case you need custom sorting and/or filtering you should subclass `TableHeaderItem` and override needed functions.

     * class FilterableHeaderItem extends TableHeaderItem {
     *     // custom filter function
     *     filter(item: TableItem): boolean {
     *         if (typeof item.data === "string" && item.data.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 ||
     *         item.data.name && item.data.name.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 ||
     *         item.data.surname && item.data.surname.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0) {
     *             return false;
     *         }
     *         return true;
     *     }
     *
     *     set filterCount(n) {}
     *     get filterCount() {
     *         return (this.filterData && this.filterData.data && this.filterData.data.length > 0) ? 1 : 0;
     *     }
     *
     *     // used for custom sorting
     *     compare(one: TableItem, two: TableItem) {
     *         const stringOne = (one.data.name || one.data.surname || one.data).toLowerCase();
     *         const stringTwo = (two.data.name || two.data.surname || two.data).toLowerCase();
     *
     *         if (stringOne > stringTwo) {
     *             return 1;
     *         } else if (stringOne < stringTwo) {
     *             return -1;
     *         } else {
     *             return 0;
     *         }
     *     }
     * }
     *

See `TableHeaderItem` class for more information.

## No data template

When table has no data to show, it can show a message you provide it instead.

     * <ibm-table [model]="model">No data.</ibm-table>
     *

... will show `No data.` message, but you can get creative and provide any template you want to replace table's default `tbody`.

## Use pagination as table footer

     * <ibm-pagination [model]="model" (selectPage)="selectPage($event)"></ibm-pagination>
     *

`selectPage()` function should fetch the data from backend, create new `data`, apply it to `model.data`, and update `model.currentPage`.

If the data your server returns is a two dimensional array of objects, it would look something like this:

     * selectPage(page) {
     *     this.getPage(page).then((data: Array<Array<any>>) => {
     *         // set the data and update page
     *         this.model.data = this.prepareData(data);
     *         this.model.currentPage = page;
     *     });
     * }
     *
     * protected prepareData(data: Array<Array<any>>) {
     *     // create new data from the service data
     *     let newData = [];
     *     data.forEach(dataRow => {
     *         let row = [];
     *         dataRow.forEach(dataElement => {
     *             row.push(new TableItem({
     *                 data: dataElement,
     *                 template: typeof dataElement === "string" ? undefined : this.paginationTableItemTemplate
     *                 // your template can handle all the data types so you don't have to conditionally set it
     *                 // you can also set different templates for different columns based on index
     *             }));
     *         });
     *         newData.push(row);
     *     });
     *     return newData;
     * }
     *

../../iframe.html?id=table--basic

### Implements

`AfterViewInit` `OnDestroy`

### Metadata

selector | `ibm-table`
template |
    <table
    	ibmTable
    	[sortable]="sortable"
    	[noBorder]="noBorder"
    	[ngClass]="{'bx--data-table--sticky-header': stickyHeader}"
    	[size]="size"
    	[striped]="striped"
    	[skeleton]="skeleton">
    	<thead
    		ibmTableHead
    		[sortable]="sortable"
    		(deselectAll)="onDeselectAll()"
    		(selectAll)="onSelectAll()"
    		(sort)="sort.emit($event)"
    		[checkboxHeaderLabel]="getCheckboxHeaderLabel()"
    		[filterTitle]="getFilterTitle()"
    		[model]="model"
    		[size]="size"
    		[selectAllCheckbox]="selectAllCheckbox"
    		[selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
    		[showSelectionColumn]="showSelectionColumn"
    		[enableSingleSelect]="enableSingleSelect"
    		[skeleton]="skeleton"
    		[sortAscendingLabel]="sortAscendingLabel"
    		[sortDescendingLabel]="sortDescendingLabel"
    		[stickyHeader]="stickyHeader">
    	</thead>
    	<tbody
    		ibmTableBody
    		(deselectRow)="onSelectRow($event)"
    		(scroll)="onScroll($event)"
    		(selectRow)="onSelectRow($event)"
    		[checkboxRowLabel]="getCheckboxRowLabel()"
    		[enableSingleSelect]="enableSingleSelect"
    		(rowClick)="onRowClick($event)"
    		[expandButtonAriaLabel]="expandButtonAriaLabel"
    		[model]="model"
    		[size]="size"
    		[ngStyle]="{'overflow-y': 'scroll'}"
    		[selectionLabelColumn]="selectionLabelColumn"
    		[showSelectionColumn]="showSelectionColumn"
    		[skeleton]="skeleton"
    		*ngIf="!noData; else noDataTemplate">
    	</tbody>
    	<ng-template #noDataTemplate><ng-content></ng-content></ng-template>
    	<tfoot>
    		<ng-template
    			[ngTemplateOutlet]="footerTemplate">
    		</ng-template>
    		<tr *ngIf="this.model.isLoading">
    			<td class="table_loading-indicator">
    				<div class="bx--loading bx--loading--small">
    					<svg class="bx--loading__svg" viewBox="-75 -75 150 150">
    						<circle class="bx--loading__stroke" cx="0" cy="0" r="37.5" />
    					</svg>
    				</div>
    			</td>
    		</tr>
    		<tr *ngIf="this.model.isEnd">
    			<td class="table_end-indicator">
    				<h5>{{getEndOfDataText() | async}}</h5>
    				<button (click)="scrollToTop($event)" class="btn--secondary-sm">
    					{{getScrollTopText() | async}}
    				</button>
    			</td>
    		</tr>
    	</tfoot>
    </table>

### Index

###### Properties
Protected _checkboxHeaderLabel Protected _checkboxRowLabel Protected _endOfDataText Protected _expandButtonAriaLabel Protected _filterTitle Protected _isDataGrid Protected _model Protected _scrollTopText Protected _sortAscendingLabel Protected _sortDescendingLabel Public columnDraggedHoverIndex Public columnDraggedPosition Protected columnResizeMouseX Protected columnResizeWidth Protected interactionModel Protected interactionPositionSubscription Public isColumnDragging Protected isViewReady Protected mouseMoveSubscription Protected mouseUpSubscription Protected positionSubscription selectAllCheckbox selectAllCheckboxSomeSelected Protected subscriptions
###### Methods
columnDragEnd columnDragEnter columnDragLeave columnDragover columnDragStart columnDrop columnResizeEnd columnResizeProgress columnResizeStart disableDataGridInteractions enableDataGridInteractions Static focus getCheckboxHeaderLabel getCheckboxRowLabel getEndOfDataText getExpandButtonAriaLabel getFilterTitle getScrollTopText getSelectionLabelValue getSortAscendingLabel getSortDescendingLabel ngAfterViewInit ngOnDestroy onDeselectAll onRowClick onScroll onSelectAll onSelectRow resetTabIndex scrollToTop Static setTabIndex Static skeletonModel updateSelectAllCheckbox
###### Inputs
columnsDraggable columnsResizable enableRowSelect enableSingleSelect expandButtonAriaLabel footerTemplate isDataGrid model noBorder scrollLoadDistance selectionLabelColumn showSelectionColumn size skeleton sortable sortAscendingLabel sortDescendingLabel stickyHeader striped translations
###### Outputs
deselectAll deselectRow rowClick scrollLoad selectAll selectRow sort
###### Accessors
model isDataGrid enableRowSelect expandButtonAriaLabel sortDescendingLabel sortAscendingLabel translations noData

### Constructor

`constructor(elementRef: ElementRef, applicationRef: ApplicationRef, i18n: I18n)`
Defined in src/table/table.component.ts:584
Creates an instance of Table. Parameters :
Name | Type | Optional
elementRef | `ElementRef` | No
applicationRef | `ApplicationRef` | No
i18n | `I18n` | No

### Inputs

`columnsDraggable` | Set to `true` to enable users to drag and drop columns. Changing the column order in table changes table model. Be aware of it when you add additional data to the model. Default value : `false`
Defined in src/table/table.component.ts:424

`columnsResizable` | Set to `true` to enable users to resize columns. Works for columns with width set in pixels. Default value : `false`
Defined in src/table/table.component.ts:415

`enableRowSelect` | Controls whether to show the selection checkboxes column or not. Type : `boolean`
Defined in src/table/table.component.ts:385

`enableSingleSelect` | Controls whether to enable multiple or single row selection. Default value : `false`
Defined in src/table/table.component.ts:401

`expandButtonAriaLabel` |
Defined in src/table/table.component.ts:427

`footerTemplate` | Set footer template to customize what is displayed in the tfoot section of the table Type : `TemplateRef<any>`
Defined in src/table/table.component.ts:483

`isDataGrid` | Set to `true` for a data grid with keyboard interactions. Type : `boolean`
Defined in src/table/table.component.ts:354

`model` | `TableModel` with data the table is to display.
Defined in src/table/table.component.ts:305

`noBorder` | Default value : `true`
Defined in src/table/table.component.ts:371

`scrollLoadDistance` | Distance (in px) from the bottom that view has to reach before `scrollLoad` event is emitted. Default value : `0`
Defined in src/table/table.component.ts:407

`selectionLabelColumn` | Used to populate the row selection checkbox label with a useful value if set. Example:
         * <ibm-table [selectionLabelColumn]="0"></ibm-table>
         * <!-- results in aria-label="Select first column value"
         * (where "first column value" is the value of the first column in the row -->
         *
Type : `number`
Defined in src/table/table.component.ts:495

`showSelectionColumn` | Controls whether to show the selection checkboxes column or not. Default value : `true`
Defined in src/table/table.component.ts:396

`size` | Size of the table rows. Type : `"sm" | "sh" | "md" | "lg"` Default value : `"md"`
Defined in src/table/table.component.ts:346

`skeleton` | Set to `true` for a loading table. Default value : `false`
Defined in src/table/table.component.ts:350

`sortable` | Setting sortable to false will disable all headers including headers which are sortable. Is is possible to set the sortable state on the header item to disable/enable sorting for only some headers. Default value : `true`
Defined in src/table/table.component.ts:369

`sortAscendingLabel` |
Defined in src/table/table.component.ts:441

`sortDescendingLabel` |
Defined in src/table/table.component.ts:434

`stickyHeader` | Set to `true` to stick the header to the top of the table Default value : `false`
Defined in src/table/table.component.ts:478

`striped` | Set to `false` to remove table rows (zebra) stripes. Default value : `true`
Defined in src/table/table.component.ts:473

`translations` | Expects an object that contains some or all of:
         * {
         *        "FILTER": "Filter",
         *        "END_OF_DATA": "You've reached the end of your content",
         *        "SCROLL_TOP": "Scroll to top",
         *        "CHECKBOX_HEADER": "Select all rows",
         *        "CHECKBOX_ROW": "Select row"
         * }
         *
Defined in src/table/table.component.ts:461

### Outputs

`deselectAll` | Emits if all rows are deselected. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:515

`deselectRow` | Emits if a single row is deselected. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:529

`rowClick` | Emits if a row item excluding expandButtons, checkboxes, or radios is clicked. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:534

`scrollLoad` | Emits when table requires more data to be loaded. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:539

`selectAll` | Emits if all rows are selected. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:508

`selectRow` | Emits if a single row is selected. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:522

`sort` | Emits an index of the column that wants to be sorted. `$event` Type: `EventEmitter`
Defined in src/table/table.component.ts:501

### Methods

columnDragEnd
`columnDragEnd(event, columnIndex)`
Defined in src/table/table.component.ts:755
Parameters :
Name | Optional
event | No
columnIndex | No
Returns : `void`

columnDragEnter
`columnDragEnter(event, position, columnIndex)`
Defined in src/table/table.component.ts:760
Parameters :
Name | Optional
event | No
position | No
columnIndex | No
Returns : `void`

columnDragLeave
`columnDragLeave(event, position, columnIndex)`
Defined in src/table/table.component.ts:765
Parameters :
Name | Optional
event | No
position | No
columnIndex | No
Returns : `void`

columnDragover
`columnDragover(event, position, columnIndex)`
Defined in src/table/table.component.ts:769
Parameters :
Name | Optional
event | No
position | No
columnIndex | No
Returns : `void`

columnDragStart
`columnDragStart(event, columnIndex)`
Defined in src/table/table.component.ts:749
Parameters :
Name | Optional
event | No
columnIndex | No
Returns : `void`

columnDrop
`columnDrop(event, position, columnIndex)`
Defined in src/table/table.component.ts:777
Parameters :
Name | Optional
event | No
position | No
columnIndex | No
Returns : `void`

columnResizeEnd
`columnResizeEnd(event, column)`
Defined in src/table/table.component.ts:730
Parameters :
Name | Optional
event | No
column | No
Returns : `void`

columnResizeProgress
`columnResizeProgress(event, column)`
Defined in src/table/table.component.ts:725
Parameters :
Name | Optional
event | No
column | No
Returns : `void`

columnResizeStart
`columnResizeStart(event, column)`
Defined in src/table/table.component.ts:712
Parameters :
Name | Optional
event | No
column | No
Returns : `void`

disableDataGridInteractions
`disableDataGridInteractions()`
Defined in src/table/table.component.ts:637
Returns : `void`

enableDataGridInteractions
`enableDataGridInteractions()`
Defined in src/table/table.component.ts:609
Returns : `void`

Static focus
`focus(element: HTMLElement)`
Defined in src/table/table.component.ts:290
Parameters :
Name | Type | Optional
element | `HTMLElement` | No
Returns : `void`

getCheckboxHeaderLabel
`getCheckboxHeaderLabel()`
Defined in src/table/table.component.ts:814
Returns : `any`

getCheckboxRowLabel
`getCheckboxRowLabel()`
Defined in src/table/table.component.ts:818
Returns : `any`

getEndOfDataText
`getEndOfDataText()`
Defined in src/table/table.component.ts:822
Returns : `any`

getExpandButtonAriaLabel
`getExpandButtonAriaLabel()`
Defined in src/table/table.component.ts:804
Returns : `any`

getFilterTitle
`getFilterTitle()`
Defined in src/table/table.component.ts:830
Returns : `any`

getScrollTopText
`getScrollTopText()`
Defined in src/table/table.component.ts:826
Returns : `any`

getSelectionLabelValue
`getSelectionLabelValue(row: TableItem[])`
Defined in src/table/table.component.ts:797
Parameters :
Name | Type | Optional
row | `TableItem[]` | No
Returns : `{ value: any; }`

getSortAscendingLabel
`getSortAscendingLabel()`
Defined in src/table/table.component.ts:810
Returns : `any`

getSortDescendingLabel
`getSortDescendingLabel()`
Defined in src/table/table.component.ts:807
Returns : `any`

ngAfterViewInit
`ngAfterViewInit()`
Defined in src/table/table.component.ts:595
Returns : `void`

ngOnDestroy
`ngOnDestroy()`
Defined in src/table/table.component.ts:602
Returns : `void`

onDeselectAll
`onDeselectAll()`
Defined in src/table/table.component.ts:653
Returns : `void`

onRowClick
`onRowClick(index: number)`
Defined in src/table/table.component.ts:675
Parameters :
Name | Type | Optional
index | `number` | No
Returns : `void`

onScroll
`onScroll(event)`
Defined in src/table/table.component.ts:739
Triggered when the user scrolls on the `<tbody>` element. Emits the `scrollLoad` event. Parameters :
Name | Optional
event | No
Returns : `void`

onSelectAll
`onSelectAll()`
Defined in src/table/table.component.ts:648
Returns : `void`

onSelectRow
`onSelectRow(event)`
Defined in src/table/table.component.ts:658
Parameters :
Name | Optional
event | No
Returns : `void`

resetTabIndex
`resetTabIndex(newTabIndex)`
Defined in src/table/table.component.ts:695
Parameters :
Name | Optional | Default value
newTabIndex | No | `-1`
Returns : `void`

scrollToTop
`scrollToTop(event)`
Defined in src/table/table.component.ts:792
Triggered when the user scrolls on the `<tbody>` element. Emits the `scrollLoad` event. Parameters :
Name | Optional
event | No
Returns : `void`

Static setTabIndex
`setTabIndex(element: HTMLElement, index: "undefined" | "0")`
Defined in src/table/table.component.ts:279
Parameters :
Name | Type | Optional
element | `HTMLElement` | No
index | `"undefined" | "0"` | No
Returns : `void`

Static skeletonModel
`skeletonModel(rowCount: number, columnCount: number)`
Defined in src/table/table.component.ts:260
Creates a skeleton model with a row and column count specified by the user Example:
         * this.model = Table.skeletonModel(5, 5);
         *
Parameters :
Name | Type | Optional
rowCount | `number` | No
columnCount | `number` | No
Returns : `any`

updateSelectAllCheckbox
`updateSelectAllCheckbox()`
Defined in src/table/table.component.ts:679
Returns : `void`

### Properties

Protected _checkboxHeaderLabel
`_checkboxHeaderLabel: ```
Default value : `this.i18n.getOverridable("TABLE.CHECKBOX_HEADER")`
Defined in src/table/table.component.ts:575

Protected _checkboxRowLabel
`_checkboxRowLabel: ```
Default value : `this.i18n.getOverridable("TABLE.CHECKBOX_ROW")`
Defined in src/table/table.component.ts:576

Protected _endOfDataText
`_endOfDataText: ```
Default value : `this.i18n.getOverridable("TABLE.END_OF_DATA")`
Defined in src/table/table.component.ts:577

Protected _expandButtonAriaLabel
`_expandButtonAriaLabel: ```
Default value : `this.i18n.getOverridable("TABLE.EXPAND_BUTTON")`
Defined in src/table/table.component.ts:572

Protected _filterTitle
`_filterTitle: ```
Default value : `this.i18n.getOverridable("TABLE.FILTER")`
Defined in src/table/table.component.ts:579

Protected _isDataGrid
`_isDataGrid: ```
Default value : `false`
Defined in src/table/table.component.ts:562

Protected _model
`_model: `TableModel``
Type : `TableModel`
Defined in src/table/table.component.ts:561

Protected _scrollTopText
`_scrollTopText: ```
Default value : `this.i18n.getOverridable("TABLE.SCROLL_TOP")`
Defined in src/table/table.component.ts:578

Protected _sortAscendingLabel
`_sortAscendingLabel: ```
Default value : `this.i18n.getOverridable("TABLE.SORT_ASCENDING")`
Defined in src/table/table.component.ts:574

Protected _sortDescendingLabel
`_sortDescendingLabel: ```
Default value : `this.i18n.getOverridable("TABLE.SORT_DESCENDING")`
Defined in src/table/table.component.ts:573

Public columnDraggedHoverIndex
`columnDraggedHoverIndex: ```
Default value : `-1`
Defined in src/table/table.component.ts:558

Public columnDraggedPosition
`columnDraggedPosition: `string``
Type : `string`
Default value : `""`
Defined in src/table/table.component.ts:559

Protected columnResizeMouseX
`columnResizeMouseX: `number``
Type : `number`
Defined in src/table/table.component.ts:582

Protected columnResizeWidth
`columnResizeWidth: `number``
Type : `number`
Defined in src/table/table.component.ts:581

Protected interactionModel
`interactionModel: `DataGridInteractionModel``
Type : `DataGridInteractionModel`
Defined in src/table/table.component.ts:569

Protected interactionPositionSubscription
`interactionPositionSubscription: `Subscription``
Type : `Subscription`
Defined in src/table/table.component.ts:570

Public isColumnDragging
`isColumnDragging: ```
Default value : `false`
Defined in src/table/table.component.ts:557

Protected isViewReady
`isViewReady: ```
Default value : `false`
Defined in src/table/table.component.ts:564

Protected mouseMoveSubscription
`mouseMoveSubscription: `Subscription``
Type : `Subscription`
Defined in src/table/table.component.ts:583

Protected mouseUpSubscription
`mouseUpSubscription: `Subscription``
Type : `Subscription`
Defined in src/table/table.component.ts:584

Protected positionSubscription
`positionSubscription: `Subscription``
Type : `Subscription`
Defined in src/table/table.component.ts:567

selectAllCheckbox
`selectAllCheckbox: ```
Default value : `false`
Defined in src/table/table.component.ts:544
Controls if all checkboxes are viewed as selected.

selectAllCheckboxSomeSelected
`selectAllCheckboxSomeSelected: ```
Default value : `false`
Defined in src/table/table.component.ts:549
Controls the indeterminate state of the header checkbox.

Protected subscriptions
`subscriptions: ```
Default value : `new Subscription()`
Defined in src/table/table.component.ts:566

### Accessors

model
get `model()`
Defined in src/table/table.component.ts:339
set `model(m)`
Defined in src/table/table.component.ts:305
`TableModel` with data the table is to display. Parameters :
Name | Optional
m | No
Returns : `void`

isDataGrid
get `isDataGrid()`
Defined in src/table/table.component.ts:373
set `isDataGrid(value: boolean)`
Defined in src/table/table.component.ts:354
Set to `true` for a data grid with keyboard interactions. Parameters :
Name | Type | Optional
value | `boolean` | No
Returns : `void`

enableRowSelect
get `enableRowSelect()`
Defined in src/table/table.component.ts:389
set `enableRowSelect(value: boolean)`
Defined in src/table/table.component.ts:385
Controls whether to show the selection checkboxes column or not. Parameters :
Name | Type | Optional
value | `boolean` | No
Returns : `void`

expandButtonAriaLabel
get `expandButtonAriaLabel()`
Defined in src/table/table.component.ts:430
set `expandButtonAriaLabel(value)`
Defined in src/table/table.component.ts:427
Parameters :
Name | Optional
value | No
Returns : `void`

sortDescendingLabel
get `sortDescendingLabel()`
Defined in src/table/table.component.ts:437
set `sortDescendingLabel(value)`
Defined in src/table/table.component.ts:434
Parameters :
Name | Optional
value | No
Returns : `void`

sortAscendingLabel
get `sortAscendingLabel()`
Defined in src/table/table.component.ts:444
set `sortAscendingLabel(value)`
Defined in src/table/table.component.ts:441
Parameters :
Name | Optional
value | No
Returns : `void`

translations
set `translations(value)`
Defined in src/table/table.component.ts:461
Expects an object that contains some or all of:
         * {
         *        "FILTER": "Filter",
         *        "END_OF_DATA": "You've reached the end of your content",
         *        "SCROLL_TOP": "Scroll to top",
         *        "CHECKBOX_HEADER": "Select all rows",
         *        "CHECKBOX_ROW": "Select row"
         * }
         *
Parameters :
Name | Optional
value | No
Returns : `void`

noData
get `noData()`
Defined in src/table/table.component.ts:551

    import {
    	Component,
    	ApplicationRef,
    	Input,
    	Output,
    	EventEmitter,
    	ElementRef,
    	AfterViewInit,
    	TemplateRef,
    	OnDestroy,
    	HostBinding
    } from "@angular/core";
    import { Subscription, fromEvent, Observable } from "rxjs";

    import { TableModel } from "./table-model.class";
    import { TableHeaderItem } from "./table-header-item.class";
    import { TableItem } from "./table-item.class";

    import { getFocusElementList, tabbableSelectorIgnoreTabIndex } from "../common/tab.service";
    import { I18n, Overridable } from "./../i18n/i18n.module";
    import { merge } from "./../utils/object";
    import { DataGridInteractionModel } from "./data-grid-interaction-model.class";
    import { TableDomAdapter } from "./table-adapter.class";

    export interface TableTranslations {
    	FILTER: string;
    	END_OF_DATA: string;
    	SCROLL_TOP: string;
    	CHECKBOX_HEADER: string;
    	CHECKBOX_ROW: string;
    }

    /**
     * Build your table with this component by extending things that differ from default.
     *
     * [See demo](../../?path=/story/table--basic)
     *
     * Instead of the usual write-your-own-html approach you had with `<table>`,
     * carbon table uses model-view-controller approach.
     *
     * Here, you create a view (with built-in controller) and provide it a model.
     * Changes you make to the model are reflected in the view. Provide same model you use
     * in the table to the `<ibm-pagination>` components.
     * They provide a different view over the same data.
     *
     * ## Basic usage
     *
     * ```html
     * <ibm-table [model]="model"></ibm-table>
     * ```
     *
     * ```typescript
     * public model = new TableModel();
     *
     * this.model.data = [
     * 	[new TableItem({data: "asdf"}), new TableItem({data: "qwer"})],
     * 	[new TableItem({data: "csdf"}), new TableItem({data: "zwer"})],
     * 	[new TableItem({data: "bsdf"}), new TableItem({data: "swer"})],
     * 	[new TableItem({data: "csdf"}), new TableItem({data: "twer"})]
     * ];
     * ```
     *
     * ## Customization
     *
     * If you have custom data in your table, you need a way to display it. You can do that
     * by providing a template to `TableItem`.
     *
     * ```html
     * <ng-template #customTableItemTemplate let-data="data">
     * 	<a [routerLink]="data.link">{{data.name}} {{data.surname}}</a>
     * </ng-template>
     * ```
     *
     * ```typescript
     * customTableItemTemplate: TemplateRef<any>;
     *
     * this.customModel.data = [
     * 	[new TableItem({data: "asdf"}), new TableItem({data: {name: "Lessy", link: "/table"}, template: this.customTableItemTemplate})],
     * 	[new TableItem({data: "csdf"}), new TableItem({data: "swer"})],
     * 	[new TableItem({data: "bsdf"}), new TableItem({data: {name: "Alice", surname: "Bob"}, template: this.customTableItemTemplate})],
     * 	[new TableItem({data: "csdf"}), new TableItem({data: "twer"})],
     * ];
     * ```
     *
     * ### Sorting and filtering
     *
     * In case you need custom sorting and/or filtering you should subclass `TableHeaderItem`
     * and override needed functions.
     *
     * ```typescript
     * class FilterableHeaderItem extends TableHeaderItem {
     * 	// custom filter function
     * 	filter(item: TableItem): boolean {
     * 		if (typeof item.data === "string" && item.data.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 ||
     * 		item.data.name && item.data.name.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 ||
     * 		item.data.surname && item.data.surname.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0) {
     * 			return false;
     * 		}
     * 		return true;
     * 	}
     *
     * 	set filterCount(n) {}
     * 	get filterCount() {
     * 		return (this.filterData && this.filterData.data && this.filterData.data.length > 0) ? 1 : 0;
     * 	}
     *
     * 	// used for custom sorting
     * 	compare(one: TableItem, two: TableItem) {
     * 		const stringOne = (one.data.name || one.data.surname || one.data).toLowerCase();
     * 		const stringTwo = (two.data.name || two.data.surname || two.data).toLowerCase();
     *
     * 		if (stringOne > stringTwo) {
     * 			return 1;
     * 		} else if (stringOne < stringTwo) {
     * 			return -1;
     * 		} else {
     * 			return 0;
     * 		}
     * 	}
     * }
     * ```
     *
     * See `TableHeaderItem` class for more information.
     *
     * ## No data template
     *
     * When table has no data to show, it can show a message you provide it instead.
     *
     * ```html
     * <ibm-table [model]="model">No data.</ibm-table>
     * ```
     *
     * ... will show `No data.` message, but you can get creative and provide any template you want
     * to replace table's default `tbody`.
     *
     * ## Use pagination as table footer
     *
     * ```html
     * <ibm-pagination [model]="model" (selectPage)="selectPage($event)"></ibm-pagination>
     * ```
     *
     * `selectPage()` function should fetch the data from backend, create new `data`, apply it to `model.data`,
     * and update `model.currentPage`.
     *
     * If the data your server returns is a two dimensional array of objects, it would look something like this:
     *
     * ```typescript
     * selectPage(page) {
     * 	this.getPage(page).then((data: Array<Array<any>>) => {
     * 		// set the data and update page
     * 		this.model.data = this.prepareData(data);
     * 		this.model.currentPage = page;
     * 	});
     * }
     *
     * protected prepareData(data: Array<Array<any>>) {
     * 	// create new data from the service data
     * 	let newData = [];
     * 	data.forEach(dataRow => {
     * 		let row = [];
     * 		dataRow.forEach(dataElement => {
     * 			row.push(new TableItem({
     * 				data: dataElement,
     * 				template: typeof dataElement === "string" ? undefined : this.paginationTableItemTemplate
     * 				// your template can handle all the data types so you don't have to conditionally set it
     * 				// you can also set different templates for different columns based on index
     * 			}));
     * 		});
     * 		newData.push(row);
     * 	});
     * 	return newData;
     * }
     * ```
     *
     * <example-url>../../iframe.html?id=table--basic</example-url>
     */
    @Component({
    	selector: "ibm-table",
    	template: `
    	<table
    		ibmTable
    		[sortable]="sortable"
    		[noBorder]="noBorder"
    		[ngClass]="{'bx--data-table--sticky-header': stickyHeader}"
    		[size]="size"
    		[striped]="striped"
    		[skeleton]="skeleton">
    		<thead
    			ibmTableHead
    			[sortable]="sortable"
    			(deselectAll)="onDeselectAll()"
    			(selectAll)="onSelectAll()"
    			(sort)="sort.emit($event)"
    			[checkboxHeaderLabel]="getCheckboxHeaderLabel()"
    			[filterTitle]="getFilterTitle()"
    			[model]="model"
    			[size]="size"
    			[selectAllCheckbox]="selectAllCheckbox"
    			[selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
    			[showSelectionColumn]="showSelectionColumn"
    			[enableSingleSelect]="enableSingleSelect"
    			[skeleton]="skeleton"
    			[sortAscendingLabel]="sortAscendingLabel"
    			[sortDescendingLabel]="sortDescendingLabel"
    			[stickyHeader]="stickyHeader">
    		</thead>
    		<tbody
    			ibmTableBody
    			(deselectRow)="onSelectRow($event)"
    			(scroll)="onScroll($event)"
    			(selectRow)="onSelectRow($event)"
    			[checkboxRowLabel]="getCheckboxRowLabel()"
    			[enableSingleSelect]="enableSingleSelect"
    			(rowClick)="onRowClick($event)"
    			[expandButtonAriaLabel]="expandButtonAriaLabel"
    			[model]="model"
    			[size]="size"
    			[ngStyle]="{'overflow-y': 'scroll'}"
    			[selectionLabelColumn]="selectionLabelColumn"
    			[showSelectionColumn]="showSelectionColumn"
    			[skeleton]="skeleton"
    			*ngIf="!noData; else noDataTemplate">
    		</tbody>
    		<ng-template #noDataTemplate><ng-content></ng-content></ng-template>
    		<tfoot>
    			<ng-template
    				[ngTemplateOutlet]="footerTemplate">
    			</ng-template>
    			<tr *ngIf="this.model.isLoading">
    				<td class="table_loading-indicator">
    					<div class="bx--loading bx--loading--small">
    						<svg class="bx--loading__svg" viewBox="-75 -75 150 150">
    							<circle class="bx--loading__stroke" cx="0" cy="0" r="37.5" />
    						</svg>
    					</div>
    				</td>
    			</tr>
    			<tr *ngIf="this.model.isEnd">
    				<td class="table_end-indicator">
    					<h5>{{getEndOfDataText() | async}}</h5>
    					<button (click)="scrollToTop($event)" class="btn--secondary-sm">
    						{{getScrollTopText() | async}}
    					</button>
    				</td>
    			</tr>
    		</tfoot>
    	</table>
    	`
    })
    export class Table implements AfterViewInit, OnDestroy {
    	/**
    	 * Creates a skeleton model with a row and column count specified by the user
    	 *
    	 * Example:
    	 *
    	 * ```typescript
    	 * this.model = Table.skeletonModel(5, 5);
    	 * ```
    	 */
    	static skeletonModel(rowCount: number, columnCount: number) {
    		const model = new TableModel();
    		let header = new Array<TableHeaderItem>();
    		let data = new Array<Array<TableItem>>();
    		let row = new Array<TableItem>();

    		for (let i = 0; i < columnCount; i++) {
    			header.push(new TableHeaderItem());
    			row.push(new TableItem());
    		}
    		for (let i = 0; i < rowCount - 1; i++) {
    			data.push(row);
    		}

    		model.header = header;
    		model.data = data;
    		return model;
    	}

    	static setTabIndex(element: HTMLElement, index: -1 | 0) {
    		const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex);
    		if (element.firstElementChild && element.firstElementChild.classList.contains("bx--table-sort")) {
    			focusElementList[1].tabIndex = index;
    		} else if (focusElementList.length > 0) {
    			focusElementList[0].tabIndex = index;
    		} else {
    			element.tabIndex = index;
    		}
    	}

    	static focus(element: HTMLElement) {
    		const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex);
    		if (element.firstElementChild && element.firstElementChild.classList.contains("bx--table-sort")) {
    			focusElementList[1].focus();
    		} else if (focusElementList.length > 0) {
    			focusElementList[0].focus();
    		} else {
    			element.focus();
    		}
    	}

    	/**
    	 * `TableModel` with data the table is to display.
    	 */
    	@Input()
    	set model(m: TableModel) {
    		if (this._model) {
    			this.subscriptions.unsubscribe();
    		}

    		this._model = m;

    		const rowsChange = this._model.rowsSelectedChange.subscribe(() => this.updateSelectAllCheckbox());
    		const dataChange = this._model.dataChange.subscribe(() => {
    			if (this.isDataGrid) {
    				this.resetTabIndex();
    			}
    			this.updateSelectAllCheckbox();
    		});

    		this.subscriptions.add(rowsChange);
    		this.subscriptions.add(dataChange);

    		if (this.isDataGrid) {
    			const expandedChange = this._model.rowsExpandedChange.subscribe(() => {
    				// Allows the expanded row to have a focus state when it exists in the DOM
    				setTimeout(() => {
    					const expandedRows = this.elementRef.nativeElement.querySelectorAll(".bx--expandable-row:not(.bx--parent-row)");
    					Array.from<any>(expandedRows).forEach(row => {
    						if (row.firstElementChild.tabIndex === undefined || row.firstElementChild.tabIndex !== -1) {
    							row.firstElementChild.tabIndex = -1;
    						}
    					});
    				});
    			});
    			this.subscriptions.add(expandedChange);
    		}
    	}

    	get model(): TableModel {
    		return this._model;
    	}

    	/**
    	 * Size of the table rows.
    	 */
    	@Input() size: "sm" | "sh" | "md" | "lg" = "md";
    	/**
    	 * Set to `true` for a loading table.
    	 */
    	@Input() skeleton = false;
    	/**
    	 * Set to `true` for a data grid with keyboard interactions.
    	 */
    	@Input() set isDataGrid(value: boolean) {
    		this._isDataGrid = value;
    		if (this.isViewReady) {
    			if (value) {
    				this.enableDataGridInteractions();
    			} else {
    				this.disableDataGridInteractions();
    			}
    		}
    	}

    	/**
    	 * Setting sortable to false will disable all headers including headers which are sortable. Is is
    	 * possible to set the sortable state on the header item to disable/enable sorting for only some headers.
    	 */
    	@Input() sortable = true;

    	@Input() noBorder = true;

    	get isDataGrid(): boolean {
    		return this._isDataGrid;
    	}

    	/**
    	 * Controls whether to show the selection checkboxes column or not.
    	 *
    	 * @deprecated in the next major carbon-components-angular version in favor of
    	 * `showSelectionColumn` because of new attribute `enableSingleSelect`
    	 *  please use `showSelectionColumn` instead
    	 */
    	@Input()
    	set enableRowSelect(value: boolean) {
    		this.showSelectionColumn = value;
    	}

    	get enableRowSelect () {
    		return this.showSelectionColumn;
    	}

    	/**
    	 * Controls whether to show the selection checkboxes column or not.
    	 */
    	@Input() showSelectionColumn = true;

    	/**
    	 * Controls whether to enable multiple or single row selection.
    	 */
    	@Input() enableSingleSelect = false;

    	/**
    	 * Distance (in px) from the bottom that view has to reach before
    	 * `scrollLoad` event is emitted.
    	 */
    	@Input() scrollLoadDistance = 0;

    	/**
    	 * Set to `true` to enable users to resize columns.
    	 *
    	 * Works for columns with width set in pixels.
    	 *
    	 */
    	@Input() columnsResizable = false;

    	/**
    	 * Set to `true` to enable users to drag and drop columns.
    	 *
    	 * Changing the column order in table changes table model. Be aware of it when you add additional data
    	 * to the model.
    	 *
    	 */
    	@Input() columnsDraggable = false;

    	@Input()
    	set expandButtonAriaLabel(value: string | Observable<string>) {
    		this._expandButtonAriaLabel.override(value);
    	}
    	get expandButtonAriaLabel() {
    		return this._expandButtonAriaLabel.value;
    	}
    	@Input()
    	set sortDescendingLabel(value: string | Observable<string>) {
    		this._sortDescendingLabel.override(value);
    	}
    	get sortDescendingLabel() {
    		return this._sortDescendingLabel.value;
    	}
    	@Input()
    	set sortAscendingLabel(value: string | Observable<string>) {
    		this._sortAscendingLabel.override(value);
    	}
    	get sortAscendingLabel() {
    		return this._sortAscendingLabel.value;
    	}

    	/**
    	 * Expects an object that contains some or all of:
    	 * ```
    	 * {
    	 *		"FILTER": "Filter",
    	 *		"END_OF_DATA": "You've reached the end of your content",
    	 *		"SCROLL_TOP": "Scroll to top",
    	 *		"CHECKBOX_HEADER": "Select all rows",
    	 *		"CHECKBOX_ROW": "Select row"
    	 * }
    	 * ```
    	 */
    	@Input()
    	set translations (value) {
    		const valueWithDefaults = merge(this.i18n.getMultiple("TABLE"), value);
    		this._filterTitle.override(valueWithDefaults.FILTER);
    		this._endOfDataText.override(valueWithDefaults.END_OF_DATA);
    		this._scrollTopText.override(valueWithDefaults.SCROLL_TOP);
    		this._checkboxHeaderLabel.override(valueWithDefaults.CHECKBOX_HEADER);
    		this._checkboxRowLabel.override(valueWithDefaults.CHECKBOX_ROW);
    	}

    	/**
    	 * Set to `false` to remove table rows (zebra) stripes.
    	 */
    	@Input() striped = true;

    	/**
    	 * Set to `true` to stick the header to the top of the table
    	 */
    	@HostBinding("class.bx--data-table_inner-container") @Input() stickyHeader = false;

    	/**
    	 * Set footer template to customize what is displayed in the tfoot section of the table
    	 */
    	@Input() footerTemplate: TemplateRef<any>;

    	/**
    	 * Used to populate the row selection checkbox label with a useful value if set.
    	 *
    	 * Example:
    	 * ```
    	 * <ibm-table [selectionLabelColumn]="0"></ibm-table>
    	 * <!-- results in aria-label="Select first column value"
    	 * (where "first column value" is the value of the first column in the row -->
    	 * ```
    	 */
    	@Input() selectionLabelColumn: number;

    	/**
    	 * Emits an index of the column that wants to be sorted.
    	 *
    	 */
    	@Output() sort = new EventEmitter<number>();

    	/**
    	 * Emits if all rows are selected.
    	 *
    	 * @param model
    	 */
    	@Output() selectAll = new EventEmitter<Object>();

    	/**
    	 * Emits if all rows are deselected.
    	 *
    	 * @param model
    	 */
    	@Output() deselectAll = new EventEmitter<Object>();

    	/**
    	 * Emits if a single row is selected.
    	 *
    	 * @param ({model: this.model, selectedRowIndex: index})
    	 */
    	@Output() selectRow = new EventEmitter<Object>();

    	/**
    	 * Emits if a single row is deselected.
    	 *
    	 * @param ({model: this.model, deselectedRowIndex: index})
    	 */
    	@Output() deselectRow = new EventEmitter<Object>();

    	/**
    	 * Emits if a row item excluding expandButtons, checkboxes, or radios is clicked.
    	 */
    	@Output() rowClick = new EventEmitter<number>();

    	/**
    	 * Emits when table requires more data to be loaded.
    	 */
    	@Output() scrollLoad = new EventEmitter<TableModel>();

    	/**
    	 * Controls if all checkboxes are viewed as selected.
    	 */
    	selectAllCheckbox = false;

    	/**
    	 * Controls the indeterminate state of the header checkbox.
    	 */
    	selectAllCheckboxSomeSelected = false;

    	get noData() {
    		return !this.model.data ||
    			this.model.data.length === 0 ||
    			this.model.data.length === 1 && this.model.data[0].length === 0;
    	}

    	public isColumnDragging = false;
    	public columnDraggedHoverIndex = -1;
    	public columnDraggedPosition = "";

    	protected _model: TableModel;
    	protected _isDataGrid = false;
    	// flag to prevent getters/setters from querying the view before it's fully instantiated
    	protected isViewReady = false;

    	protected subscriptions = new Subscription();
    	protected positionSubscription: Subscription;

    	protected interactionModel: DataGridInteractionModel;
    	protected interactionPositionSubscription: Subscription;

    	protected _expandButtonAriaLabel  = this.i18n.getOverridable("TABLE.EXPAND_BUTTON");
    	protected _sortDescendingLabel = this.i18n.getOverridable("TABLE.SORT_DESCENDING");
    	protected _sortAscendingLabel = this.i18n.getOverridable("TABLE.SORT_ASCENDING");
    	protected _checkboxHeaderLabel = this.i18n.getOverridable("TABLE.CHECKBOX_HEADER");
    	protected _checkboxRowLabel = this.i18n.getOverridable("TABLE.CHECKBOX_ROW");
    	protected _endOfDataText = this.i18n.getOverridable("TABLE.END_OF_DATA");
    	protected _scrollTopText = this.i18n.getOverridable("TABLE.SCROLL_TOP");
    	protected _filterTitle = this.i18n.getOverridable("TABLE.FILTER");

    	protected columnResizeWidth: number;
    	protected columnResizeMouseX: number;
    	protected mouseMoveSubscription: Subscription;
    	protected mouseUpSubscription: Subscription;

    	/**
    	 * Creates an instance of Table.
    	 */
    	constructor(
    		protected elementRef: ElementRef,
    		protected applicationRef: ApplicationRef,
    		protected i18n: I18n
    	) {}

    	ngAfterViewInit() {
    		this.isViewReady = true;
    		if (this.isDataGrid) {
    			this.enableDataGridInteractions();
    		}
    	}

    	ngOnDestroy() {
    		this.subscriptions.unsubscribe();
    		if (this.positionSubscription) {
    			this.positionSubscription.unsubscribe();
    		}
    	}

    	enableDataGridInteractions() {
    		// if we have an `interactioModel` we've already enabled datagrid
    		if (this.interactionModel) {
    			return;
    		}
    		const table = this.elementRef.nativeElement.querySelector("table") as HTMLTableElement;
    		const tableAdapter = new TableDomAdapter(table);
    		const keydownEventStream = fromEvent<KeyboardEvent>(table, "keydown");
    		const clickEventStream = fromEvent<MouseEvent>(table, "click");
    		this.interactionModel = new DataGridInteractionModel(keydownEventStream, clickEventStream, tableAdapter);
    		this.positionSubscription = this.interactionModel.position.subscribe(event => {
    			const [currentRow, currentColumn] = event.current;
    			const [previousRow, previousColumn] = event.previous;

    			const currentElement = tableAdapter.getCell(currentRow, currentColumn);
    			Table.setTabIndex(currentElement, 0);

    			// if the model has just initialized don't focus or reset anything
    			if (previousRow === -1 || previousColumn === -1) { return; }

    			const previousElement = tableAdapter.getCell(previousRow, previousColumn);
    			Table.setTabIndex(previousElement, -1);
    			Table.focus(currentElement);
    		});
    		// call this after assigning `this.interactionModel` since it depends on it
    		this.resetTabIndex();
    	}

    	disableDataGridInteractions() {
    		// unsubscribe first so we don't cause the focus to fly around
    		if (this.positionSubscription) {
    			this.positionSubscription.unsubscribe();
    		}
    		// undo tab indexing (also resets the model)
    		this.resetTabIndex(0);
    		// null out the model ref
    		this.interactionModel = null;
    	}

    	onSelectAll() {
    		this.model.selectAll(true);
    		this.selectAll.emit(this.model);
    	}

    	onDeselectAll() {
    		this.model.selectAll(false);
    		this.deselectAll.emit(this.model);
    	}

    	onSelectRow(event) {
    		// check for the existence of the selectedRowIndex property
    		if (Object.keys(event).includes("selectedRowIndex")) {
    			this.model.selectRow(event.selectedRowIndex, true);
    			this.selectRow.emit(event);

    			if (this.showSelectionColumn && this.enableSingleSelect) {
    				const index = event.selectedRowIndex;
    				this.model.selectAll(false);
    				this.model.selectRow(index);
    			}
    		} else {
    			this.model.selectRow(event.deselectedRowIndex, false);
    			this.deselectRow.emit(event);
    		}
    	}

    	onRowClick(index: number) {
    		this.rowClick.emit(index);
    	}

    	updateSelectAllCheckbox() {
    		const selectedRowsCount = this.model.selectedRowsCount();

    		if (selectedRowsCount <= 0) {
    			// reset select all checkbox if nothing selected
    			this.selectAllCheckbox = false;
    			this.selectAllCheckboxSomeSelected = false;
    		} else if (selectedRowsCount < this.model.data.length) {
    			this.selectAllCheckbox = false;
    			this.selectAllCheckboxSomeSelected = true;
    		} else {
    			this.selectAllCheckbox = true;
    			this.selectAllCheckboxSomeSelected = false;
    		}
    	}

    	resetTabIndex(newTabIndex = -1) {
    		// ensure the view is ready for the reset before we preform the actual reset
    		setTimeout(() => {
    			// reset all the tabIndexes we can find
    			const focusElementList = getFocusElementList(this.elementRef.nativeElement, tabbableSelectorIgnoreTabIndex);
    			if (focusElementList) {
    				focusElementList.forEach(tabbable => {
    					tabbable.tabIndex = newTabIndex;
    				});
    			}
    			// reset interaction model positions and tabIndexes
    			if (this.interactionModel) {
    				this.interactionModel.resetTabIndexes(newTabIndex);
    			}
    		});
    	}

    	columnResizeStart(event, column) {
    		this.columnResizeWidth = parseInt(column.style.width, 10);
    		this.columnResizeMouseX = event.clientX;
    		event.preventDefault();

    		this.mouseMoveSubscription = fromEvent(document.body, "mousemove").subscribe(event => {
    			this.columnResizeProgress(event, column);
    		});
    		this.mouseUpSubscription = fromEvent(document.body, "mouseup").subscribe(event => {
    			this.columnResizeEnd(event, column);
    		});
    	}

    	columnResizeProgress(event, column) {
    		const move = event.clientX - this.columnResizeMouseX;
    		column.style.width = `${this.columnResizeWidth + move}px`;
    	}

    	columnResizeEnd(event, column) {
    		this.mouseMoveSubscription.unsubscribe();
    		this.mouseUpSubscription.unsubscribe();
    	}

    	/**
    	 * Triggered when the user scrolls on the `<tbody>` element.
    	 * Emits the `scrollLoad` event.
    	 */
    	onScroll(event) {
    		const distanceFromBottom = event.target.scrollHeight - event.target.clientHeight - event.target.scrollTop;

    		if (distanceFromBottom <= this.scrollLoadDistance) {
    			this.scrollLoad.emit(this.model);
    		} else {
    			this.model.isEnd = false;
    		}
    	}

    	columnDragStart(event, columnIndex) {
    		this.isColumnDragging = true;
    		this.columnDraggedHoverIndex = columnIndex;
    		event.dataTransfer.setData("columnIndex", JSON.stringify(columnIndex));
    	}

    	columnDragEnd(event, columnIndex) {
    		this.isColumnDragging = false;
    		this.columnDraggedHoverIndex = -1;
    	}

    	columnDragEnter(event, position, columnIndex) {
    		this.columnDraggedPosition = position;
    		this.columnDraggedHoverIndex = columnIndex;
    	}

    	columnDragLeave(event, position, columnIndex) {
    		this.columnDraggedPosition = "";
    	}

    	columnDragover(event, position, columnIndex) {
    		this.columnDraggedHoverIndex = columnIndex;
    		this.columnDraggedPosition = position;

    		// needed to tell browser to allow dropping
    		event.preventDefault();
    	}

    	columnDrop(event, position, columnIndex) {
    		this.isColumnDragging = false;
    		this.columnDraggedHoverIndex = -1;
    		this.columnDraggedPosition = "";

    		this.model.moveColumn(
    			parseInt(event.dataTransfer.getData("columnIndex"), 10),
    			columnIndex + (position === "right" ? 1 : 0)
    		);
    	}

    	/**
    	 * Triggered when the user scrolls on the `<tbody>` element.
    	 * Emits the `scrollLoad` event.
    	 */
    	scrollToTop(event) {
    		event.target.parentElement.parentElement.parentElement.parentElement.children[1].scrollTop = 0;
    		this.model.isEnd = false;
    	}

    	getSelectionLabelValue(row: TableItem[]) {
    		if (!this.selectionLabelColumn) {
    			return { value: this.i18n.get().TABLE.ROW };
    		}
    		return { value: row[this.selectionLabelColumn].data };
    	}

    	getExpandButtonAriaLabel() {
    		return this._expandButtonAriaLabel.subject;
    	}
    	getSortDescendingLabel() {
    		return this._sortDescendingLabel.subject;
    	}
    	getSortAscendingLabel() {
    		return this._sortAscendingLabel.subject;
    	}

    	getCheckboxHeaderLabel() {
    		return this._checkboxHeaderLabel.subject;
    	}

    	getCheckboxRowLabel() {
    		return this._checkboxRowLabel.subject;
    	}

    	getEndOfDataText() {
    		return this._endOfDataText.subject;
    	}

    	getScrollTopText() {
    		return this._scrollTopText.subject;
    	}

    	getFilterTitle() {
    		return this._filterTitle.subject;
    	}

    }

Legend
Html element
Component
Html element with directive

# result-matching ""

# No results matching ""