diff --git a/src/app/components/components/data-table/data-table.component.html b/src/app/components/components/data-table/data-table.component.html index ed91d8e330..9b1d7c1d64 100644 --- a/src/app/components/components/data-table/data-table.component.html +++ b/src/app/components/components/data-table/data-table.component.html @@ -224,12 +224,14 @@

Paging Bar / Search Box / Sortable components

[data]="filteredData" [columns]="columns" [selectable]="selectable" + [clickable]="clickable" [multiple]="multiple" [sortable]="true" [sortBy]="sortBy" [(ngModel)]="selectedRows" [sortOrder]="sortOrder" - (sortChange)="sort($event)"> + (sortChange)="sort($event)" + (rowClick)="showAlert($event)">

No results to display.

@@ -260,6 +262,9 @@

No results to display.

#dataTable [data]="filteredData" [columns]="columns" + [selectable]="selectable" + [clickable]="clickable" + [multiple]="multiple" [sortable]="true" [sortBy]="sortBy" [sortOrder]="sortOrder" @@ -353,8 +358,11 @@

No results to display.

Selectable rows - - Select multiple rows + + Clickable rows + + + Multiple rows (shift + click for range selection)
diff --git a/src/app/components/components/data-table/data-table.component.ts b/src/app/components/components/data-table/data-table.component.ts index 2802a661a7..baf5e89feb 100644 --- a/src/app/components/components/data-table/data-table.component.ts +++ b/src/app/components/components/data-table/data-table.component.ts @@ -30,9 +30,13 @@ export class DataTableDemoComponent implements OnInit { name: 'columns?', type: 'ITdDataTableColumn[]', }, { - description: `Enables row selection events, hover and selected row states.`, + description: `Enables row selection, click events and selected row state.`, name: 'selectable?', type: 'boolean', + }, { + description: `Enables row click events and hover row state.`, + name: 'clickable?', + type: 'boolean', }, { description: `Enables multiple row selection. [selectable] needs to be enabled.`, name: 'multiple?', @@ -66,6 +70,11 @@ export class DataTableDemoComponent implements OnInit { Emits an [ITdDataTableSelectAllEvent] implemented object.`, name: 'selectAll', type: `function()`, + }, { + description: `Event emitted when a row is clicked. + Emits an [ITdDataTableRowClickEvent] implemented object.`, + name: 'rowClick', + type: `function()`, }, { description: `Refreshes data table and updates [data] and [columns]`, name: 'refresh', @@ -267,6 +276,7 @@ export class DataTableDemoComponent implements OnInit { ]; basicData: any[] = this.data.slice(0, 4); selectable: boolean = true; + clickable: boolean = false; multiple: boolean = true; filterColumn: boolean = true; @@ -340,4 +350,10 @@ export class DataTableDemoComponent implements OnInit { this.columns.forEach((c: any) => c.tooltip = `This is ${c.label}!`); } } + + showAlert(event: any): void { + this._dialogService.openAlert({ + message: 'You clicked on row: ' + event.row.name, + }); + } } diff --git a/src/platform/core/data-table/_data-table-theme.scss b/src/platform/core/data-table/_data-table-theme.scss index 91159dfa6a..3e9a2015fd 100644 --- a/src/platform/core/data-table/_data-table-theme.scss +++ b/src/platform/core/data-table/_data-table-theme.scss @@ -46,13 +46,23 @@ } } &.mat-selectable tbody > tr.td-data-table-row { - &:not([disabled]):hover { + &:not([disabled]):not(.mat-selected):focus { background-color: mat-color($background, 'hover'); } &.mat-selected { background-color: mat-color($accent, 0.12); } } + &.mat-clickable tbody > tr.td-data-table-row { + &:not([disabled]){ + &:hover { + background-color: mat-color($background, 'hover'); + } + &:active { + background-color: mat-color($accent, 0.12); + } + } + } } .mat-selected-title { background-color: mat-color($accent, 0.12); diff --git a/src/platform/core/data-table/data-table-row/data-table-row.component.ts b/src/platform/core/data-table/data-table-row/data-table-row.component.ts index 72b48701ff..7d003fb05a 100644 --- a/src/platform/core/data-table/data-table-row/data-table-row.component.ts +++ b/src/platform/core/data-table/data-table-row/data-table-row.component.ts @@ -11,5 +11,9 @@ export class TdDataTableRowComponent { constructor(private _elementRef: ElementRef, private _renderer: Renderer2) { this._renderer.addClass(this._elementRef.nativeElement, 'td-data-table-row'); } + + focus(): void { + this._elementRef.nativeElement.focus(); + } } diff --git a/src/platform/core/data-table/data-table.component.html b/src/platform/core/data-table/data-table.component.html index 504573660d..fca74c66fd 100644 --- a/src/platform/core/data-table/data-table.component.html +++ b/src/platform/core/data-table/data-table.component.html @@ -1,6 +1,7 @@
+ [class.mat-selectable]="isSelectable" + [class.mat-clickable]="isClickable"> + [tabIndex]="isSelectable ? 0 : -1" + [class.mat-selected]="(isClickable || isSelectable) && isRowSelected(row)" + *ngFor="let row of data; let rowIndex = index" + (click)="handleRowClick(row, $event, rowIndex)" + (keyup)="isSelectable && _rowKeyup($event, row, rowIndex)" + (keydown.space)="blockEvent($event)" + (keydown.shift.space)="blockEvent($event)" + (keydown.shift)="disableTextSelection()" + (keyup.shift)="enableTextSelection()">
+ (click)="selectAll(!checkBoxAll.checked)" + (keyup.enter)="selectAll(!checkBoxAll.checked)" + (keyup.space)="selectAll(!checkBoxAll.checked)" + (keydown.space)="blockEvent($event)"> {{column.label}}
+ [state]="isRowSelected(row) ? 'checked' : 'unchecked'" + (mousedown)="disableTextSelection()" + (mouseup)="enableTextSelection()" + (click)="select(row, $event, rowIndex)"> { CovalentDataTableModule, ], declarations: [ - TdDataTableBasicComponent, + TdDataTableBasicTestComponent, TdDataTableSelectableTestComponent, + TdDataTableRowClickTestComponent, ], providers: [ TdDataTableService, @@ -37,8 +39,8 @@ describe('Component: DataTable', () => { it('should set hidden and not get search hits and set it to false and get search results', (done: DoneFn) => { inject([TdDataTableService], (tdDataTableService: TdDataTableService) => { - let fixture: ComponentFixture = TestBed.createComponent(TdDataTableBasicComponent); - let component: TdDataTableBasicComponent = fixture.debugElement.componentInstance; + let fixture: ComponentFixture = TestBed.createComponent(TdDataTableBasicTestComponent); + let component: TdDataTableBasicTestComponent = fixture.debugElement.componentInstance; component.columns[1].hidden = false; // backwards compatability test @@ -85,8 +87,8 @@ describe('Component: DataTable', () => { it('should set filter and not get search hits and set it to false and get search results', (done: DoneFn) => { inject([TdDataTableService], (tdDataTableService: TdDataTableService) => { - let fixture: ComponentFixture = TestBed.createComponent(TdDataTableBasicComponent); - let component: TdDataTableBasicComponent = fixture.debugElement.componentInstance; + let fixture: ComponentFixture = TestBed.createComponent(TdDataTableBasicTestComponent); + let component: TdDataTableBasicTestComponent = fixture.debugElement.componentInstance; component.columns[1].filter = false; @@ -169,7 +171,7 @@ describe('Component: DataTable', () => { expect(dataTableComponent.indeterminate).toBeFalsy(); expect(dataTableComponent.allSelected).toBeFalsy(); // select a row with a click event - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[2].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[2].triggerEventHandler('click', new Event('click')); fixture.detectChanges(); fixture.whenStable().then(() => { // check to see if its in indeterminate state @@ -225,23 +227,23 @@ describe('Component: DataTable', () => { expect(dataTableComponent.indeterminate).toBeFalsy(); expect(dataTableComponent.allSelected).toBeFalsy(); // select a row with a click event - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[2].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[2].triggerEventHandler('click', new Event('click')); fixture.detectChanges(); fixture.whenStable().then(() => { // check to see if its in indeterminate state expect(dataTableComponent.indeterminate).toBeTruthy(); expect(dataTableComponent.allSelected).toBeFalsy(); // select the rest of the rows - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[1].triggerEventHandler('click', new Event('click')); - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[3].triggerEventHandler('click', new Event('click')); - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[4].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[0].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[1].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[3].triggerEventHandler('click', new Event('click')); fixture.detectChanges(); fixture.whenStable().then(() => { // check to see if its in indeterminate state and allSelected expect(dataTableComponent.indeterminate).toBeTruthy(); expect(dataTableComponent.allSelected).toBeTruthy(); // unselect one of the rows - fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[2].triggerEventHandler('click', new Event('click')); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[2].triggerEventHandler('click', new Event('click')); fixture.detectChanges(); fixture.whenStable().then(() => { // check to see if its in indeterminate state and not allSelected @@ -255,8 +257,80 @@ describe('Component: DataTable', () => { })(); }); - }); + it('should shift click and select a range of rows', + (done: DoneFn) => { inject([], () => { + let fixture: ComponentFixture = TestBed.createComponent(TdDataTableSelectableTestComponent); + let element: DebugElement = fixture.debugElement; + let component: TdDataTableSelectableTestComponent = fixture.debugElement.componentInstance; + + component.selectable = true; + component.multiple = true; + component.columns = [ + { name: 'sku', label: 'SKU #' }, + { name: 'item', label: 'Item name' }, + { name: 'price', label: 'Price (US$)', numeric: true }, + ]; + + component.data = [{ sku: '1452-2', item: 'Pork Chops', price: 32.11 }, + { sku: '1421-0', item: 'Prime Rib', price: 41.15 }, + { sku: '1452-1', item: 'Sirlone', price: 22.11 }, + { sku: '1421-3', item: 'T-Bone', price: 51.15 }]; + + fixture.detectChanges(); + fixture.whenStable().then(() => { + let dataTableComponent: TdDataTableComponent = fixture.debugElement.query(By.directive(TdDataTableComponent)).componentInstance; + // check how many rows (without counting the columns) were rendered + expect(fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent)).length - 1).toBe(4); + // check to see checkboxes states + expect(dataTableComponent.indeterminate).toBeFalsy(); + expect(dataTableComponent.allSelected).toBeFalsy(); + + fixture.detectChanges(); + fixture.whenStable().then(() => { + // select the first and last row with shift key also selected and should then select all checkboxes + let clickEvent: MouseEvent = document.createEvent('MouseEvents'); + // the 12th parameter below 'true' sets the shift key to be clicked at the same time as as the mouse click + clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, true/*shiftkey*/, false, 0, document.body.parentNode); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[0].nativeElement.dispatchEvent(clickEvent); + fixture.debugElement.queryAll(By.directive(MdPseudoCheckbox))[3].nativeElement.dispatchEvent(clickEvent); + fixture.detectChanges(); + fixture.whenStable().then(() => { + // check to see if allSelected is true + expect(dataTableComponent.allSelected).toBeTruthy(); + done(); + }); + }); + }); + })(); + }); + + it('should click on a row and see the rowClick Event', + async(inject([], () => { + let fixture: ComponentFixture = TestBed.createComponent(TdDataTableRowClickTestComponent); + let component: TdDataTableRowClickTestComponent = fixture.debugElement.componentInstance; + + let eventSpy: jasmine.Spy = spyOn(component, 'clickEvent'); + + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[1].nativeElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(eventSpy.calls.count()).toBe(0); + component.clickable = true; + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.debugElement.queryAll(By.directive(TdDataTableRowComponent))[1].nativeElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(eventSpy.calls.count()).toBe(1); + }); + }); + }); + }); + }))); + }); }); @Component({ @@ -266,7 +340,7 @@ describe('Component: DataTable', () => { [columns]="columns"> `, }) -class TdDataTableBasicComponent { +class TdDataTableBasicTestComponent { data: any[] = [ { sku: '1452-2', item: 'Pork Chops', price: 32.11 }, { sku: '1421-0', item: 'Prime Rib', price: 41.15 }, @@ -293,3 +367,28 @@ class TdDataTableSelectableTestComponent { selectable: boolean = false; multiple: boolean = false; } + +@Component({ + template: ` + + `, +}) +class TdDataTableRowClickTestComponent { + data: any[] = [ + { sku: '1452-2', item: 'Pork Chops', price: 32.11 }, + { sku: '1421-0', item: 'Prime Rib', price: 41.15 }, + ]; + columns: ITdDataTableColumn[] = [ + { name: 'sku', label: 'SKU #' }, + { name: 'item', label: 'Item name' }, + { name: 'price', label: 'Price (US$)', numeric: true }, + ]; + clickable: boolean = false; + clickEvent(): void { + /* noop */ + } +} diff --git a/src/platform/core/data-table/data-table.component.ts b/src/platform/core/data-table/data-table.component.ts index 0410ecf6a5..4598af0d2b 100644 --- a/src/platform/core/data-table/data-table.component.ts +++ b/src/platform/core/data-table/data-table.component.ts @@ -1,7 +1,11 @@ import { Component, Input, Output, EventEmitter, forwardRef, ChangeDetectionStrategy, ChangeDetectorRef, - ContentChildren, TemplateRef, AfterContentInit, QueryList } from '@angular/core'; + ContentChildren, TemplateRef, AfterContentInit, QueryList, Inject, Optional, ViewChildren } from '@angular/core'; +import { DOCUMENT } from '@angular/platform-browser'; import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; +import { ENTER, SPACE, UP_ARROW, DOWN_ARROW } from '@angular/material'; + +import { TdDataTableRowComponent } from './data-table-row/data-table-row.component'; import { ITdDataTableSortChangeEvent } from './data-table-column/data-table-column.component'; import { TdDataTableTemplateDirective } from './directives/data-table-template.directive'; @@ -42,6 +46,15 @@ export interface ITdDataTableSelectAllEvent { selected: boolean; } +export interface ITdDataTableRowClickEvent { + row: any; +} + +export enum TdDataTableArrowKeyDirection { + Ascending = 'ASC', + Descending = 'DESC', +} + @Component({ providers: [ TD_DATA_TABLE_CONTROL_VALUE_ACCESSOR ], selector: 'td-data-table', @@ -62,6 +75,7 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI private _data: any[]; private _columns: ITdDataTableColumn[]; private _selectable: boolean = false; + private _clickable: boolean = false; private _multiple: boolean = true; private _allSelected: boolean = false; private _indeterminate: boolean = false; @@ -71,10 +85,17 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI private _sortBy: ITdDataTableColumn; private _sortOrder: TdDataTableSortingOrder = TdDataTableSortingOrder.Ascending; + /** shift select */ + private _lastSelectedIndex: number = -1; + private _selectedBeforeLastIndex: number = -1; + private _lastArrowKeyDirection: TdDataTableArrowKeyDirection; + /** template fetching support */ private _templateMap: Map> = new Map>(); @ContentChildren(TdDataTableTemplateDirective) _templates: QueryList; + @ViewChildren(TdDataTableRowComponent) _rows: QueryList; + /** * Returns true if all values are selected. */ @@ -163,6 +184,19 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI return this._selectable; } + /** + * clickable?: boolean + * Enables row click events, hover. + * Defaults to 'false' + */ + @Input('clickable') + set clickable(clickable: string | boolean) { + this._clickable = clickable !== '' ? (clickable === 'true' || clickable === true) : true; + } + get isClickable(): boolean { + return this._clickable; + } + /** * multiple?: boolean * Enables multiple row selection. [selectable] needs to be enabled. @@ -247,6 +281,13 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI */ @Output('rowSelect') onRowSelect: EventEmitter = new EventEmitter(); + /** + * rowClick?: function + * Event emitted when a row is clicked. + * Emits an [ITdDataTableRowClickEvent] implemented object. + */ + @Output('rowClick') onRowClick: EventEmitter = new EventEmitter(); + /** * selectAll?: function * Event emitted when all rows are selected/deselected by the all checkbox. [selectable] needs to be enabled. @@ -255,7 +296,8 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI @Output('selectAll') onSelectAll: EventEmitter = new EventEmitter(); - constructor(private _changeDetectorRef: ChangeDetectorRef) {} + constructor(@Optional() @Inject(DOCUMENT) private _document: any, + private _changeDetectorRef: ChangeDetectorRef) {} /** * Loads templates and sets them in a map for faster access. @@ -333,32 +375,70 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI } /** - * Selects or clears a row depending on 'checked' value + * Selects or clears a row depending on 'checked' value if the row 'isSelectable' + * handles cntrl clicks and shift clicks for multi-select */ - select(row: any, checked: boolean, event: Event): void { - event.preventDefault(); - // clears all the fields for the dataset - if (!this._multiple) { - this.clearModel(); - } - - if (checked) { - this._value.push(row); - } else { - // if selection is done by a [uniqueId] it uses it to compare, else it compares by reference. - if (this.uniqueId) { - row = this._value.filter((val: any) => { - return val[this.uniqueId] === row[this.uniqueId]; - })[0]; + select(row: any, event: Event, currentSelected: number): void { + if (this.isSelectable) { + this.blockEvent(event); + this._doSelection(row); + + // Check to see if Shift key is selected and need to select everything in between + let mouseEvent: MouseEvent = event as MouseEvent; + if (this.isMultiple && mouseEvent && mouseEvent.shiftKey && this._lastSelectedIndex > -1) { + let firstIndex: number = currentSelected; + let lastIndex: number = this._lastSelectedIndex; + if (currentSelected > this._lastSelectedIndex) { + firstIndex = this._lastSelectedIndex; + lastIndex = currentSelected; + } + for (let i: number = firstIndex + 1; i < lastIndex; i++) { + this._doSelection(this._data[i]); + } } - let index: number = this._value.indexOf(row); - if (index > -1) { - this._value.splice(index, 1); + // set the last selected attribute unless the last selected unchecked a row + if (this.isRowSelected(this._data[currentSelected])) { + this._selectedBeforeLastIndex = this._lastSelectedIndex; + this._lastSelectedIndex = currentSelected; + } else { + this._lastSelectedIndex = this._selectedBeforeLastIndex; + } + // everything is unselected so start over + if (!this._indeterminate && !this._allSelected) { + this._lastSelectedIndex = -1; } } - this._calculateCheckboxState(); - this.onRowSelect.emit({row: row, selected: checked}); - this.onChange(this._value); + } + + /** + * Overrides the onselectstart method of the document so other text on the page + * doesn't get selected when doing shift selections. + */ + disableTextSelection(): void { + if (this._document) { + this._document.onselectstart = function(): boolean { + return false; + }; + } + } + + /** + * Resets the original onselectstart method. + */ + enableTextSelection(): void { + if (this._document) { + this._document.onselectstart = undefined; + } + } + + /** + * emits the onRowClickEvent when a row is clicked + * if clickable is true and selectable is false then select the row + */ + handleRowClick(row: any, event: Event, currentSelected: number): void { + if (this.isClickable) { + this.onRowClick.emit({row: row}); + } } /** @@ -375,6 +455,82 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI this.onSortChange.next({ name: this._sortBy.name, order: this._sortOrder }); } + /** + * Handle all keyup events when focusing a data table row + */ + _rowKeyup(event: KeyboardEvent, row: any, index: number): void { + let length: number; + let rows: TdDataTableRowComponent[]; + switch (event.keyCode) { + case ENTER: + case SPACE: + /** if user presses enter or space, the row should be selected */ + this.select(row, event, index); + break; + case UP_ARROW: + rows = this._rows.toArray(); + length = rows.length; + + // check to see if changing direction and need to toggle the current row + if (this._lastArrowKeyDirection === TdDataTableArrowKeyDirection.Descending) { + index++; + } + /** + * if users presses the up arrow, we focus the prev row + * unless its the first row, then we move to the last row + */ + if (index === 0) { + if (!event.shiftKey) { + rows[length - 1].focus(); + } + } else { + rows[index - 1].focus(); + } + this.blockEvent(event); + if (this.isMultiple && event.shiftKey) { + this._doSelection(this._data[index - 1]); + // if the checkboxes are all unselected then start over otherwise handle changing direction + this._lastArrowKeyDirection = (!this._allSelected && !this._indeterminate) ? undefined : TdDataTableArrowKeyDirection.Ascending; + } + break; + case DOWN_ARROW: + rows = this._rows.toArray(); + length = rows.length; + + // check to see if changing direction and need to toggle the current row + if (this._lastArrowKeyDirection === TdDataTableArrowKeyDirection.Ascending) { + index--; + } + /** + * if users presses the down arrow, we focus the next row + * unless its the last row, then we move to the first row + */ + if (index === (length - 1)) { + if (!event.shiftKey) { + rows[0].focus(); + } + } else { + rows[index + 1].focus(); + } + this.blockEvent(event); + if (this.isMultiple && event.shiftKey) { + this._doSelection(this._data[index + 1]); + // if the checkboxes are all unselected then start over otherwise handle changing direction + this._lastArrowKeyDirection = (!this._allSelected && !this._indeterminate) ? undefined : TdDataTableArrowKeyDirection.Descending; + } + break; + default: + // default + } + } + + /** + * Method to prevent the default events + */ + blockEvent(event: Event): void { + event.preventDefault(); + } + /** * Implemented as part of ControlValueAccessor. */ @@ -405,6 +561,33 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI } } + /** + * Does the actual Row Selection + */ + private _doSelection(row: any): void { + let wasSelected: boolean = this.isRowSelected(row); + if (!this._multiple) { + this.clearModel(); + } + if (!wasSelected) { + this._value.push(row); + } else { + // if selection is done by a [uniqueId] it uses it to compare, else it compares by reference. + if (this.uniqueId) { + row = this._value.filter((val: any) => { + return val[this.uniqueId] === row[this.uniqueId]; + })[0]; + } + let index: number = this._value.indexOf(row); + if (index > -1) { + this._value.splice(index, 1); + } + } + this._calculateCheckboxState(); + this.onRowSelect.emit({row: row, selected: this.isRowSelected(row)}); + this.onChange(this._value); + } + /** * Calculate all the state of all checkboxes */ @@ -436,5 +619,4 @@ export class TdDataTableComponent implements ControlValueAccessor, AfterContentI } } } - } diff --git a/src/platform/core/data-table/data-table.module.ts b/src/platform/core/data-table/data-table.module.ts index 532e5d9e40..6897c24a14 100644 --- a/src/platform/core/data-table/data-table.module.ts +++ b/src/platform/core/data-table/data-table.module.ts @@ -21,7 +21,7 @@ const TD_DATA_TABLE: Type[] = [ TdDataTableTableComponent, ]; -export { TdDataTableComponent, TdDataTableSortingOrder, +export { TdDataTableComponent, TdDataTableSortingOrder, ITdDataTableRowClickEvent, ITdDataTableColumn, ITdDataTableSelectEvent, ITdDataTableSelectAllEvent } from './data-table.component'; export { TdDataTableService } from './services/data-table.service'; export { TdDataTableColumnComponent,