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 7284d85fd6..2875f92888 100644 --- a/src/app/components/components/data-table/data-table.component.html +++ b/src/app/components/components/data-table/data-table.component.html @@ -289,7 +289,7 @@

No results to display.

columns: ITdDataTableColumn[] = [ { name: 'sku', label: 'SKU #', tooltip: 'Stock Keeping Unit' }, { name: 'item', label: 'Item name' }, - { name: 'price', label: 'Price (US$)', numeric: true, format: v => v.toFixed(2) }, + { name: 'price', label: 'Price (US$)', numeric: true, format: v => v.toFixed(2), filter: true }, ]; filteredData: any[] = this.data; @@ -328,7 +328,13 @@

No results to display.

filter(): void { let newData: any[] = this.data; - newData = this._dataTableService.filterData(newData, this.searchTerm, true); + let nonSearchAbleColumns: string[] = this.columns + .filter((column: ITdDataTableColumn) => { + return (typeof column.filter !== undefined && column.filter === false); + }).map((column: ITdDataTableColumn) => { + return column.name; + }); + newData = this._dataTableService.filterData(newData, this.searchTerm, true, nonSearchAbleColumns); this.filteredTotal = newData.length; newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder); newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize); @@ -342,18 +348,26 @@

No results to display.

- - - +
+ + Selectable rows + + + Select multiple rows + +
+ +
+ + Tooltips on column headers + +
+ +
+ + Type column is searchable (search for candy) + +
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 c07b2e9ff9..43091c3a0e 100644 --- a/src/app/components/components/data-table/data-table.component.ts +++ b/src/app/components/components/data-table/data-table.component.ts @@ -90,6 +90,10 @@ export class DataTableDemoComponent implements OnInit { description: `Sets the sort order of column. Defaults to 'ASC' or TdDataTableSortingOrder.Ascending`, name: 'sortOrder', type: `['ASC' | 'DESC'] or TdDataTableSortingOrder`, + }, { + description: `When set to false this column will be excluded from searches using the filterData method.`, + name: 'filter?', + type: 'boolean', }, { description: `Sets column to active state when 'true'. Defaults to 'false'`, name: 'active', @@ -106,9 +110,10 @@ export class DataTableDemoComponent implements OnInit { }]; serviceAttrs: Object[] = [{ - description: `Searches [data] parameter for [searchTerm] matches and returns a new array with them.`, + description: `Searches [data] parameter for [searchTerm] matches and returns a new array with them. + Any column names passed in with [nonSearchAbleColumns] will be excluded in the search.`, name: 'filterData', - type: `function(data: any[], searchTerm: string, ignoreCase: boolean)`, + type: `function(data: any[], searchTerm: string, ignoreCase: boolean, nonSearchAbleColumns: string[])`, }, { description: `Sorts [data] parameter by [sortBy] and [sortOrder] and returns the sorted data.`, name: 'sortData', @@ -121,8 +126,8 @@ export class DataTableDemoComponent implements OnInit { columns: ITdDataTableColumn[] = [ { name: 'name', label: 'Dessert (100g serving)', sortable: true }, - { name: 'type', label: 'Type' }, - { name: 'calories', label: 'Calories', numeric: true, format: NUMBER_FORMAT, sortable: true }, + { name: 'type', label: 'Type', filter: true }, + { name: 'calories', label: 'Calories', numeric: true, format: NUMBER_FORMAT, sortable: true}, { name: 'fat', label: 'Fat (g)', numeric: true, format: DECIMAL_FORMAT, sortable: true }, { name: 'carbs', label: 'Carbs (g)', numeric: true, format: NUMBER_FORMAT }, { name: 'protein', label: 'Protein (g)', numeric: true, format: DECIMAL_FORMAT }, @@ -257,8 +262,9 @@ export class DataTableDemoComponent implements OnInit { }, ]; basicData: any[] = this.data.slice(0, 4); - selectable: boolean = false; - multiple: boolean = false; + selectable: boolean = true; + multiple: boolean = true; + filterColumn: boolean = true; filteredData: any[] = this.data; filteredTotal: number = this.data.length; @@ -309,25 +315,19 @@ export class DataTableDemoComponent implements OnInit { filter(): void { let newData: any[] = this.data; - newData = this._dataTableService.filterData(newData, this.searchTerm, true); + let nonSearchAbleColumns: string[] = this.columns + .filter((column: ITdDataTableColumn) => { + return (typeof column.filter !== undefined && column.filter === false); + }).map((column: ITdDataTableColumn) => { + return column.name; + }); + newData = this._dataTableService.filterData(newData, this.searchTerm, true, nonSearchAbleColumns); this.filteredTotal = newData.length; newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder); newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize); this.filteredData = newData; } - toggleSelectable(): void { - this.selectable = !this.selectable; - } - - toggleMultiple(): void { - this.multiple = !this.multiple; - } - - areTooltipsOn(): boolean { - return this.columns[0].hasOwnProperty('tooltip'); - } - toggleTooltips(): void { if (this.columns[0].tooltip) { this.columns.forEach((c: any) => delete c.tooltip); diff --git a/src/platform/core/data-table/data-table.component.spec.ts b/src/platform/core/data-table/data-table.component.spec.ts new file mode 100644 index 0000000000..c4b18b876e --- /dev/null +++ b/src/platform/core/data-table/data-table.component.spec.ts @@ -0,0 +1,111 @@ +import { + TestBed, + inject, + async, + ComponentFixture, +} from '@angular/core/testing'; +import 'hammerjs'; +import { Component } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { TdDataTableComponent, ITdDataTableColumn } from './data-table.component'; +import { TdDataTableService } from './services/data-table.service'; +import { CovalentDataTableModule } from './data-table.module'; +import { NgModule, DebugElement } from '@angular/core'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +describe('Component: TdDataTableComponent', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + CovalentDataTableModule, + ], + declarations: [ + TestFilterColumnComponent, + ], + providers: [ + TdDataTableService, + ], + }); + TestBed.compileComponents(); + })); + + it('should create the component', (done: DoneFn) => { + let fixture: ComponentFixture = TestBed.createComponent(TestFilterColumnComponent); + let component: TestFilterColumnComponent = fixture.debugElement.componentInstance; + + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(component).toBeTruthy(); + done(); + }); + }); + + 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(TestFilterColumnComponent); + let component: TestFilterColumnComponent = fixture.debugElement.componentInstance; + + fixture.detectChanges(); + fixture.whenStable().then(() => { + let columns: ITdDataTableColumn[] = fixture.debugElement.query(By.directive(TdDataTableComponent)).componentInstance.columns; + expect(columns[1].filter).toBe(false); + + let newData: any[] = component.data; + // backwards compatability test + newData = tdDataTableService.filterData(newData, '1452-2', true); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(newData.length).toBe(1); + + let nonSearchAbleColumns: string[] = component.columns + .filter((column: ITdDataTableColumn) => { + return (typeof column.filter !== undefined && column.filter === false); + }).map((column: ITdDataTableColumn) => { + return column.name; + }); + newData = component.data; + newData = tdDataTableService.filterData(newData, 'Pork', true, nonSearchAbleColumns); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(newData.length).toBe(0); + + fixture.detectChanges(); + fixture.whenStable().then(() => { + newData = component.data; + newData = tdDataTableService.filterData(newData, 'Pork', true, []); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(newData.length).toBe(1); + done(); + }); + }); + }); + }); + }); + })(); + }); +}); + +@Component({ + template: ` + + `, +}) +class TestFilterColumnComponent { + 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 #', tooltip: 'Stock Keeping Unit' }, + { name: 'item', label: 'Item name', filter: false }, + { name: 'price', label: 'Price (US$)', numeric: true }, + ]; + + filteredData: any[] = this.data; +} diff --git a/src/platform/core/data-table/data-table.component.ts b/src/platform/core/data-table/data-table.component.ts index 311a985448..af005b754c 100644 --- a/src/platform/core/data-table/data-table.component.ts +++ b/src/platform/core/data-table/data-table.component.ts @@ -28,6 +28,7 @@ export interface ITdDataTableColumn { format?: (value: any) => any; nested?: boolean; sortable?: boolean; + filter?: boolean; } export interface ITdDataTableSelectEvent { diff --git a/src/platform/core/data-table/services/data-table.service.ts b/src/platform/core/data-table/services/data-table.service.ts index 9bfe10a308..f4b1f3ecc4 100644 --- a/src/platform/core/data-table/services/data-table.service.ts +++ b/src/platform/core/data-table/services/data-table.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; -import { TdDataTableSortingOrder } from '../data-table.component'; +import { TdDataTableSortingOrder, ITdDataTableColumn } from '../data-table.component'; @Injectable() export class TdDataTableService { @@ -13,14 +13,16 @@ export class TdDataTableService { * * Searches [data] parameter for [searchTerm] matches and returns a new array with them. */ - filterData(data: any[], searchTerm: string, ignoreCase: boolean = false): any[] { + filterData(data: any[], searchTerm: string, ignoreCase: boolean = false, excludedColumns?: string[]): any[] { let filter: string = searchTerm ? (ignoreCase ? searchTerm.toLowerCase() : searchTerm) : ''; if (filter) { data = data.filter((item: any) => { const res: any = Object.keys(item).find((key: string) => { - const preItemValue: string = ('' + item[key]); - const itemValue: string = ignoreCase ? preItemValue.toLowerCase() : preItemValue; - return itemValue.indexOf(filter) > -1; + if (!excludedColumns || excludedColumns.indexOf(key) === -1) { + const preItemValue: string = ('' + item[key]); + const itemValue: string = ignoreCase ? preItemValue.toLowerCase() : preItemValue; + return itemValue.indexOf(filter) > -1; + } }); return !(typeof res === 'undefined'); });