Skip to content

Commit

Permalink
feat(data-table): ability to hide data table columns (closes #511) (#549
Browse files Browse the repository at this point in the history
)

* feat: Data Table: Hide data table columns
Added hidden property on columns to keep certain columns from being displayed or searched on in the filterData method. Also added unit tests for table and updated documentation.

Closes #511

* fixing linting

* using refresh method on datatable in demo to force change detection from data change

* fix for backward compatability on filterData, fixing unit tests, backwards compatability test, and updating demo to toggles instead of buttons

* changing toggle label to Hide calories on demo

* updating parameter on filterdata to excludedColumns, changing label in unit test file, updating demo with latest API changes

* updating documentating with correct parameter name, excludedColumns

* removing undefined check for hidden parameter

* removing undefined check for hidden parameter

* chore(data-table): remove the undefined hidden case from unit tests

* chore(data-table): refactoring unit tests to use one component

also check for hidden in the hidden use case

* chore(data-table): refactor and minimize unit test even more

added comments in certain places too
  • Loading branch information
jeremysmartt authored and emoralesb05 committed May 8, 2017
1 parent d4d90a2 commit 0ccb191
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,14 @@ <h3>No results to display.</h3>

filter(): void {
let newData: any[] = this.data;
let nonSearchAbleColumns: string[] = this.columns
let excludedColumns: string[] = this.columns
.filter((column: ITdDataTableColumn) => {
return (typeof column.filter !== undefined && column.filter === false);
return ((column.filter === undefined && column.hidden === true) ||
(column.filter !== undefined && column.filter === false));
}).map((column: ITdDataTableColumn) => {
return column.name;
});
newData = this._dataTableService.filterData(newData, this.searchTerm, true, nonSearchAbleColumns);
newData = this._dataTableService.filterData(newData, this.searchTerm, true, excludedColumns);
this.filteredTotal = newData.length;
newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder);
newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize);
Expand Down Expand Up @@ -364,6 +365,9 @@ <h3>No results to display.</h3>
</div>
<md-divider></md-divider>
<div class="pad-sm">
<md-slide-toggle color="accent" [(ngModel)]="columns[2].hidden" (change)="dataTable.refresh()">
Hide calories
</md-slide-toggle>
<md-slide-toggle color="accent" [(ngModel)]="columns[1].filter">
Type column is searchable (search for <code>candy</code>)
</md-slide-toggle>
Expand Down
17 changes: 11 additions & 6 deletions src/app/components/components/data-table/data-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component, OnInit, HostBinding } from '@angular/core';

import { slideInDownAnimation } from '../../../app.animations';

import { TdDataTableSortingOrder, TdDataTableService,
import { TdDataTableSortingOrder, TdDataTableService, TdDataTableComponent,
ITdDataTableSortChangeEvent, ITdDataTableColumn } from '../../../../platform/core';
import { IPageChangeEvent } from '../../../../platform/core';
import { TdDialogService } from '../../../../platform/core';
Expand Down Expand Up @@ -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: `Whether the column should be hidden or not. Defaults to 'false'`,
name: 'hidden',
type: `boolean`,
}, {
description: `When set to false this column will be excluded from searches using the filterData method.`,
name: 'filter?',
Expand Down Expand Up @@ -126,8 +130,8 @@ export class DataTableDemoComponent implements OnInit {

columns: ITdDataTableColumn[] = [
{ name: 'name', label: 'Dessert (100g serving)', sortable: true },
{ name: 'type', label: 'Type', filter: true },
{ 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, hidden: false },
{ 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 },
Expand Down Expand Up @@ -315,13 +319,14 @@ export class DataTableDemoComponent implements OnInit {

filter(): void {
let newData: any[] = this.data;
let nonSearchAbleColumns: string[] = this.columns
let excludedColumns: string[] = this.columns
.filter((column: ITdDataTableColumn) => {
return (typeof column.filter !== undefined && column.filter === false);
return ((column.filter === undefined && column.hidden === true) ||
(column.filter !== undefined && column.filter === false));
}).map((column: ITdDataTableColumn) => {
return column.name;
});
newData = this._dataTableService.filterData(newData, this.searchTerm, true, nonSearchAbleColumns);
newData = this._dataTableService.filterData(newData, this.searchTerm, true, excludedColumns);
this.filteredTotal = newData.length;
newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder);
newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize);
Expand Down
2 changes: 2 additions & 0 deletions src/platform/core/data-table/data-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
[active]="(column.sortable || isSortable) && column === sortByColumn"
[sortable]="column.sortable || isSortable"
[sortOrder]="sortOrderEnum"
[hidden]="column.hidden"
(sortChange)="handleSort(column)">
<span [mdTooltip]="column.tooltip">{{column.label}}</span>
</th>
Expand All @@ -31,6 +32,7 @@
</td>
<td td-data-table-cell
[numeric]="column.numeric"
[hidden]="column.hidden"
*ngFor="let column of columns">
<span class="md-body-1" *ngIf="!getTemplateRef(column.name)">{{column.format ? column.format(getCellValue(column, row)) : getCellValue(column, row)}}</span>
<ng-template
Expand Down
117 changes: 73 additions & 44 deletions src/platform/core/data-table/data-table.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import 'hammerjs';
import { Component } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TdDataTableColumnComponent } from './data-table-column/data-table-column.component';
import { TdDataTableComponent, ITdDataTableColumn } from './data-table.component';
import { TdDataTableService } from './services/data-table.service';
import { CovalentDataTableModule } from './data-table.module';
Expand All @@ -22,7 +23,7 @@ describe('Component: DataTable', () => {
CovalentDataTableModule,
],
declarations: [
TestFilterColumnComponent,
TdDataTableBasicComponent,
TdDataTableSelectableTestComponent,
],
providers: [
Expand All @@ -32,57 +33,88 @@ describe('Component: DataTable', () => {
TestBed.compileComponents();
}));

it('should create the component', (done: DoneFn) => {
let fixture: ComponentFixture<any> = TestBed.createComponent(TestFilterColumnComponent);
let component: TestFilterColumnComponent = fixture.debugElement.componentInstance;
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<any> = TestBed.createComponent(TdDataTableBasicComponent);
let component: TdDataTableBasicComponent = fixture.debugElement.componentInstance;

component.columns[1].hidden = false;
// backwards compatability test
expect(tdDataTableService.filterData(component.data, '1452-2', true).length).toBe(1);

fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component).toBeTruthy();
done();
});
fixture.detectChanges();
fixture.whenStable().then(() => {
// check if there are no hidden columns
expect(fixture.debugElement.queryAll(By.directive(TdDataTableColumnComponent))
.filter((col: DebugElement) => {
return (<any>(<HTMLElement>col.nativeElement).attributes).hidden;
}).length).toBe(0);

// check how many rows would return that contain Pork if no hidden columns
expect(tdDataTableService.filterData(component.data, 'Pork', true, component.columns
.filter((column: ITdDataTableColumn) => {
return column.hidden === true;
}).map((column: ITdDataTableColumn) => {
return column.name;
})).length).toBe(1);

component.columns[1].hidden = true;
fixture.debugElement.query(By.directive(TdDataTableComponent)).componentInstance.refresh();
fixture.detectChanges();
fixture.whenStable().then(() => {
// check if there are hidden columns
expect(fixture.debugElement.queryAll(By.directive(TdDataTableColumnComponent))
.filter((col: DebugElement) => {
return (<any>(<HTMLElement>col.nativeElement).attributes).hidden;
}).length).toBe(1);

// check how many rows would return that contain Pork if the column is hidden
expect(tdDataTableService.filterData(component.data, 'Pork', true, component.columns
.filter((column: ITdDataTableColumn) => {
return column.hidden === true;
}).map((column: ITdDataTableColumn) => {
return column.name;
})).length).toBe(0);
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<any> = TestBed.createComponent(TestFilterColumnComponent);
let component: TestFilterColumnComponent = fixture.debugElement.componentInstance;
let fixture: ComponentFixture<any> = TestBed.createComponent(TdDataTableBasicComponent);
let component: TdDataTableBasicComponent = fixture.debugElement.componentInstance;

component.columns[1].filter = false;

fixture.detectChanges();
fixture.whenStable().then(() => {
let columns: ITdDataTableColumn[] = fixture.debugElement.query(By.directive(TdDataTableComponent)).componentInstance.columns;
expect(columns[1].filter).toBe(false);
expect(component.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);
expect(tdDataTableService.filterData(component.data, '1452-2', true).length).toBe(1);

let nonSearchAbleColumns: string[] = component.columns
// check how many rows would return that contain Pork if the second column has filter = false
expect(tdDataTableService.filterData(component.data, 'Pork', true, 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();
});
});
});
})).length).toBe(0);

// set the second column as filtered
component.columns[1].filter = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
// check how many rows would return that contain Pork if the seconds column has filter = true
expect(tdDataTableService.filterData(component.data, 'Pork', true, component.columns
.filter((column: ITdDataTableColumn) => {
return (typeof column.filter !== undefined && column.filter === false);
}).map((column: ITdDataTableColumn) => {
return column.name;
})).length).toBe(1);
done();
});
});
})();
Expand All @@ -109,23 +141,20 @@ describe('Component: DataTable', () => {
@Component({
template: `
<td-data-table
#dataTable
[data]="filteredData"
[data]="data"
[columns]="columns">
</td-data-table>`,
})
class TestFilterColumnComponent {
class TdDataTableBasicComponent {
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: 'sku', label: 'SKU #' },
{ name: 'item', label: 'Item name' },
{ name: 'price', label: 'Price (US$)', numeric: true },
];

filteredData: any[] = this.data;
}

@Component({
Expand Down
1 change: 1 addition & 0 deletions src/platform/core/data-table/data-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface ITdDataTableColumn {
format?: (value: any) => any;
nested?: boolean;
sortable?: boolean;
hidden?: boolean;
filter?: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class TdDataTableService {
* - data: any[]
* - searchTerm: string
* - ignoreCase: boolean = false
* - excludedColumns: string[] = []
*
* Searches [data] parameter for [searchTerm] matches and returns a new array with them.
*/
Expand Down

0 comments on commit 0ccb191

Please sign in to comment.