carbon-components-angular
Version:
Next generation components
907 lines • 94.2 kB
JavaScript
import { Component, Input, Output, EventEmitter, HostBinding } from "@angular/core";
import { Subscription, fromEvent } 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 "carbon-components-angular/common";
import { merge } from "carbon-components-angular/utils";
import { DataGridInteractionModel } from "./data-grid-interaction-model.class";
import { TableDomAdapter } from "./table-adapter.class";
import * as i0 from "@angular/core";
import * as i1 from "carbon-components-angular/i18n";
import * as i2 from "@angular/common";
import * as i3 from "./table.directive";
import * as i4 from "./head/table-head.component";
import * as i5 from "./body/table-body.component";
/**
* Build your table with this component by extending things that differ from default.
*
* [See demo](../../?path=/story/components-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 `<cds-pagination>` components.
* They provide a different view over the same data.
*
* ## Basic usage
*
* ```html
* <cds-table [model]="model"></cds-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;
* }
* }
* }
* ```
*
* If you want to do your sorting on the backend or query for sorted data as a result of user
* clicking the table header, check table [`sort`](#sort) output documentation
*
* 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
* <cds-table [model]="model">No data.</cds-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
* <cds-pagination [model]="model" (selectPage)="selectPage($event)"></cds-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;
* }
* ```
*/
export class Table {
/**
* Creates an instance of Table.
*/
constructor(elementRef, applicationRef, i18n) {
this.elementRef = elementRef;
this.applicationRef = applicationRef;
this.i18n = i18n;
/**
* Size of the table rows.
*/
this.size = "md";
/**
* Set to `true` for a loading table.
*/
this.skeleton = false;
/**
* 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.
*/
this.sortable = true;
this.noBorder = true;
/**
* Controls whether to show the selection checkboxes column or not.
*/
this.showSelectionColumn = true;
/**
* Controls whether to enable multiple or single row selection.
*/
this.enableSingleSelect = false;
/**
* Distance (in px) from the bottom that view has to reach before
* `scrollLoad` event is emitted.
*/
this.scrollLoadDistance = 0;
/**
* Set to `false` to remove table rows (zebra) stripes.
*/
this.striped = true;
/**
* Allows table content to scroll horizontally
*/
this.tableContent = true;
/**
* Set to `true` to stick the header to the top of the table
*/
this.stickyHeader = false;
/**
* Emits an index of the column that wants to be sorted.
*
* If no observers are provided (default), table will attempt to do a simple sort of the data loaded
* into the model.
*
* If an observer is provided, table will not attempt any sorting of its own and it is up to the observer
* to sort the table. This is what you typically want if you're using a backend query to get the sorted
* data or want to sort data across multiple pages.
*
* Usage:
*
* ```typescript
* @Component({
* selector: "app-table",
* template: `
* <cds-table
* [model]="model"
* (sort)="simpleSort($event)">
* No data.
* </cds-table>
* `
* })
* export class TableApp implements OnInit, OnChanges {
* @Input() model = new TableModel();
*
* ngOnInit() {
* this.model.header = [
* new TableHeaderItem({ data: "Name" }),
* new TableHeaderItem({ data: "hwer" })
* ];
*
* this.model.data = [
* [new TableItem({ data: "Name 1" }), new TableItem({ data: "qwer" })],
* [new TableItem({ data: "Name 3" }), new TableItem({ data: "zwer" })],
* [new TableItem({ data: "Name 2" }), new TableItem({ data: "swer" })],
* [new TableItem({ data: "Name 4" }), new TableItem({data: "twer"})],
* [new TableItem({ data: "Name 5" }), new TableItem({data: "twer"})],
* [new TableItem({ data: "Name 6" }), new TableItem({data: "twer"})]
* ];
* }
*
* simpleSort(index: number) {
* // this function does a simple sort, which is the default for the table and if that's
* // all you want, you don't need to do this.
*
* // here you can query your backend and update the model.data based on the result
* if (this.model.header[index].sorted) {
* // if already sorted flip sorting direction
* this.model.header[index].ascending = this.model.header[index].descending;
* }
* this.model.sort(index);
* }
* }
* ```
*/
this.sort = new EventEmitter();
/**
* Emits if all rows are selected.
*
* @param model
*/
this.selectAll = new EventEmitter();
/**
* Emits if all rows are deselected.
*
* @param model
*/
this.deselectAll = new EventEmitter();
/**
* Emits if a single row is selected.
*
* @param ({model: this.model, selectedRowIndex: index})
*/
this.selectRow = new EventEmitter();
/**
* Emits if a single row is deselected.
*
* @param ({model: this.model, deselectedRowIndex: index})
*/
this.deselectRow = new EventEmitter();
/**
* Emits if a row item excluding expandButtons, checkboxes, or radios is clicked.
*/
this.rowClick = new EventEmitter();
/**
* Emits when table requires more data to be loaded.
*/
this.scrollLoad = new EventEmitter();
/**
* Controls if all checkboxes are viewed as selected.
*/
this.selectAllCheckbox = false;
/**
* Controls the indeterminate state of the header checkbox.
*/
this.selectAllCheckboxSomeSelected = false;
this.isColumnDragging = false;
this.columnDraggedHoverIndex = -1;
this.columnDraggedPosition = "";
this._isDataGrid = false;
// flag to prevent getters/setters from querying the view before it's fully instantiated
this.isViewReady = false;
this.subscriptions = new Subscription();
this._expandButtonAriaLabel = this.i18n.getOverridable("TABLE.EXPAND_BUTTON");
this._sortDescendingLabel = this.i18n.getOverridable("TABLE.SORT_DESCENDING");
this._sortAscendingLabel = this.i18n.getOverridable("TABLE.SORT_ASCENDING");
this._checkboxHeaderLabel = this.i18n.getOverridable("TABLE.CHECKBOX_HEADER");
this._checkboxRowLabel = this.i18n.getOverridable("TABLE.CHECKBOX_ROW");
this._endOfDataText = this.i18n.getOverridable("TABLE.END_OF_DATA");
this._scrollTopText = this.i18n.getOverridable("TABLE.SCROLL_TOP");
this._filterTitle = this.i18n.getOverridable("TABLE.FILTER");
}
/**
* 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, columnCount) {
const model = new TableModel();
let header = new Array();
let data = new Array();
let row = new Array();
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, index) {
const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex);
if (element.firstElementChild && element.firstElementChild.classList.contains("cds--table-sort") && focusElementList.length > 1) {
focusElementList[1].tabIndex = index;
}
else if (focusElementList.length > 0) {
focusElementList[0].tabIndex = index;
}
else {
element.tabIndex = index;
}
}
static focus(element) {
const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex);
if ((element.firstElementChild?.classList.contains("cds--table-sort") && focusElementList.length > 1) ||
focusElementList.length > 0) {
focusElementList[0].focus();
}
else {
element.focus();
}
}
/**
* `TableModel` with data the table is to display.
*/
set model(m) {
if (this._model) {
this.subscriptions.unsubscribe();
// Need to create a new subscription instance here because unsubscribing prevents any new subscriptions
// from being added for some reason. When a new model is set, none of the subscriptions would exist.
this.subscriptions = new Subscription();
}
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(".cds--expandable-row:not(.cds--parent-row)");
Array.from(expandedRows).forEach(row => {
if (row.firstElementChild.tabIndex === undefined || row.firstElementChild.tabIndex !== -1) {
row.firstElementChild.tabIndex = -1;
}
});
});
});
this.subscriptions.add(expandedChange);
}
}
get model() {
return this._model;
}
/**
* Set to `true` for a data grid with keyboard interactions.
*/
set isDataGrid(value) {
this._isDataGrid = value;
if (this.isViewReady) {
if (value) {
this.enableDataGridInteractions();
}
else {
this.disableDataGridInteractions();
}
}
}
get isDataGrid() {
return this._isDataGrid;
}
/**
* @todo - Enable column resize when Carbon officially supports feature
* Set to `true` to enable users to resize columns.
*
* Works for columns with width set in pixels.
*
*/
// @Input() columnsResizable = false;
/**
* @todo - Enable columns drag & drop when Carbon officially supports feature
* 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;
set expandButtonAriaLabel(value) {
this._expandButtonAriaLabel.override(value);
}
get expandButtonAriaLabel() {
return this._expandButtonAriaLabel.value;
}
set sortDescendingLabel(value) {
this._sortDescendingLabel.override(value);
}
get sortDescendingLabel() {
return this._sortDescendingLabel.value;
}
set sortAscendingLabel(value) {
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"
* }
* ```
*/
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);
}
get noData() {
return !this.model.data ||
this.model.data.length === 0 ||
this.model.data.length === 1 && this.model.data[0].length === 0;
}
ngOnInit() {
// Manually trigger check to see if all checkboxes are selected
// This is since subscription is made AFTER checkboxes are selected
this.updateSelectAllCheckbox();
}
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");
const tableAdapter = new TableDomAdapter(table);
const keydownEventStream = fromEvent(table, "keydown");
const clickEventStream = fromEvent(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;
}
// Make the previous cell unfocusable (if it's not the current)
if (previousRow !== currentRow || previousColumn !== currentColumn) {
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")) {
if (this.enableSingleSelect) {
this.model.selectAll(false);
}
this.model.selectRow(event.selectedRowIndex, true);
this.selectRow.emit(event);
}
else {
this.model.selectRow(event.deselectedRowIndex, false);
this.deselectRow.emit(event);
}
}
onRowClick(index) {
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 = true;
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));
}
doSort(index) {
if (this.sort.observers.length === 0) {
// no sort provided so do the simple sort
this.model.cycleSortState(index);
this.model.sort(index);
}
this.sort.emit(index);
}
/**
* 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) {
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;
}
}
Table.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Table, deps: [{ token: i0.ElementRef }, { token: i0.ApplicationRef }, { token: i1.I18n }], target: i0.ɵɵFactoryTarget.Component });
Table.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Table, selector: "cds-table, ibm-table", inputs: { ariaLabelledby: "ariaLabelledby", ariaDescribedby: "ariaDescribedby", model: "model", size: "size", skeleton: "skeleton", isDataGrid: "isDataGrid", sortable: "sortable", noBorder: "noBorder", showSelectionColumn: "showSelectionColumn", enableSingleSelect: "enableSingleSelect", scrollLoadDistance: "scrollLoadDistance", expandButtonAriaLabel: "expandButtonAriaLabel", sortDescendingLabel: "sortDescendingLabel", sortAscendingLabel: "sortAscendingLabel", translations: "translations", striped: "striped", stickyHeader: "stickyHeader", footerTemplate: "footerTemplate", selectionLabelColumn: "selectionLabelColumn" }, outputs: { sort: "sort", selectAll: "selectAll", deselectAll: "deselectAll", selectRow: "selectRow", deselectRow: "deselectRow", rowClick: "rowClick", scrollLoad: "scrollLoad" }, host: { properties: { "class.cds--data-table-content": "this.tableContent", "class.cds--data-table_inner-container": "this.stickyHeader" } }, ngImport: i0, template: `
<table
cdsTable
[sortable]="sortable"
[noBorder]="noBorder"
[ngClass]="{'cds--data-table--sticky-header': stickyHeader}"
[size]="size"
[striped]="striped"
[skeleton]="skeleton"
[attr.aria-labelledby]="ariaLabelledby"
[attr.aria-describedby]="ariaDescribedby">
<thead
cdsTableHead
[sortable]="sortable"
(deselectAll)="onDeselectAll()"
(selectAll)="onSelectAll()"
(sort)="doSort($event)"
[checkboxHeaderLabel]="getCheckboxHeaderLabel()"
[filterTitle]="getFilterTitle()"
[model]="model"
[selectAllCheckbox]="selectAllCheckbox"
[selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
[showSelectionColumn]="showSelectionColumn"
[enableSingleSelect]="enableSingleSelect"
[skeleton]="skeleton"
[sortAscendingLabel]="sortAscendingLabel"
[sortDescendingLabel]="sortDescendingLabel"
[stickyHeader]="stickyHeader">
</thead>
<tbody
cdsTableBody
(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="cds--loading cds--loading--small">
<svg class="cds--loading__svg" viewBox="-75 -75 150 150">
<circle class="cds--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>
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.TableDirective, selector: "[cdsTable], [ibmTable]", inputs: ["sortable", "noBorder", "striped", "skeleton", "size"] }, { kind: "component", type: i4.TableHead, selector: "[cdsTableHead], [ibmTableHead]", inputs: ["model", "showSelectionColumn", "enableSingleSelect", "selectAllCheckboxSomeSelected", "selectAllCheckbox", "skeleton", "stickyHeader", "sortable", "checkboxHeaderLabel", "sortDescendingLabel", "sortAscendingLabel", "filterTitle"], outputs: ["sort", "selectAll", "deselectAll"] }, { kind: "component", type: i5.TableBody, selector: "[cdsTableBody], [ibmTableBody]", inputs: ["model", "enableSingleSelect", "expandButtonAriaLabel", "checkboxRowLabel", "showSelectionColumn", "size", "selectionLabelColumn", "skeleton"], outputs: ["selectRow", "deselectRow", "rowClick"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Table, decorators: [{
type: Component,
args: [{ selector: "cds-table, ibm-table", template: `
<table
cdsTable
[sortable]="sortable"
[noBorder]="noBorder"
[ngClass]="{'cds--data-table--sticky-header': stickyHeader}"
[size]="size"
[striped]="striped"
[skeleton]="skeleton"
[attr.aria-labelledby]="ariaLabelledby"
[attr.aria-describedby]="ariaDescribedby">
<thead
cdsTableHead
[sortable]="sortable"
(deselectAll)="onDeselectAll()"
(selectAll)="onSelectAll()"
(sort)="doSort($event)"
[checkboxHeaderLabel]="getCheckboxHeaderLabel()"
[filterTitle]="getFilterTitle()"
[model]="model"
[selectAllCheckbox]="selectAllCheckbox"
[selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
[showSelectionColumn]="showSelectionColumn"
[enableSingleSelect]="enableSingleSelect"
[skeleton]="skeleton"
[sortAscendingLabel]="sortAscendingLabel"
[sortDescendingLabel]="sortDescendingLabel"
[stickyHeader]="stickyHeader">
</thead>
<tbody
cdsTableBody
(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="cds--loading cds--loading--small">
<svg class="cds--loading__svg" viewBox="-75 -75 150 150">
<circle class="cds--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>
`, styles: [":host{display:block}\n"] }]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ApplicationRef }, { type: i1.I18n }]; }, propDecorators: { ariaLabelledby: [{
type: Input
}], ariaDescribedby: [{
type: Input
}], model: [{
type: Input
}], size: [{
type: Input
}], skeleton: [{
type: Input
}], isDataGrid: [{
type: Input
}], sortable: [{
type: Input
}], noBorder: [{
type: Input
}], showSelectionColumn: [{
type: Input
}], enableSingleSelect: [{
type: Input
}], scrollLoadDistance: [{
type: Input
}], expandButtonAriaLabel: [{
type: Input
}], sortDescendingLabel: [{
type: Input
}], sortAscendingLabel: [{
type: Input
}], translations: [{
type: Input
}], striped: [{
type: Input
}], tableContent: [{
type: HostBinding,
args: ["class.cds--data-table-content"]
}], stickyHeader: [{
type: HostBinding,
args: ["class.cds--data-table_inner-container"]
}, {
type: Input
}], footerTemplate: [{
type: Input
}], selectionLabelColumn: [{
type: Input
}], sort: [{
type: Output
}], selectAll: [{
type: Output
}], deselectAll: [{
type: Output
}], selectRow: [{
type: Output
}], deselectRow: [{
type: Output
}], rowClick: [{
type: Output
}], scrollLoad: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RhYmxlL3RhYmxlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUVULEtBQUssRUFFTCxNQUFNLEVBQ04sWUFBWSxFQUtaLFdBQVcsRUFDWCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUUzRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUvQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUV2RyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDeEQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDL0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHVCQUF1QixDQUFDOzs7Ozs7O0FBR3hEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnSkc7QUFnRkgsTUFBTSxPQUFPLEtBQUs7SUF3WWpCOztPQUVHO0lBQ0gsWUFDVyxVQUFzQixFQUN0QixjQUE4QixFQUM5QixJQUFVO1FBRlYsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN0QixtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsU0FBSSxHQUFKLElBQUksQ0FBTTtRQXBTckI7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