Skip to content

Commit

Permalink
feat(stark-ui): table - Add support to show rows counter
Browse files Browse the repository at this point in the history
ISSUES CLOSED: #1244
  • Loading branch information
SuperITMan committed May 20, 2019
1 parent 93a4f34 commit 0d983a6
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@
display: flex;
justify-content: flex-end;

&.actions-alt {
flex-direction: row-reverse;
}

stark-minimap {
mat-icon {
width: 18px;
height: 18px;
}
}
}

.stark-table-rows-counter {
flex: 1;
text-align: center;
line-height: 35px;
margin-right: 16px;
}
}

.table-container {
Expand Down
119 changes: 64 additions & 55 deletions packages/stark-ui/src/modules/table/components/table.component.html
Original file line number Diff line number Diff line change
@@ -1,71 +1,80 @@
<!-- the projected detail content should be put in an ng-template so that it can be rendered multiple times in this template -->
<!-- solution taken from https://github.com/angular/angular/issues/22972#issuecomment-407358396 -->
<ng-template #tableActions>
<!-- Count of element in the table -->
<div *ngIf="showRowsCounter && dataSource" class="stark-table-rows-counter">
<span>{{ dataSource.filteredData.length }} </span>
<span translate>STARK.TABLE.ITEMS_FOUND</span>
</div>

<stark-pagination htmlSuffixId="{{ htmlId }}-pagination" [paginationConfig]="paginationConfig" mode="compact"></stark-pagination>

<button *ngIf="isMultiSortEnabled" (click)="openMultiSortDialog()" mat-icon-button>
<mat-icon
class="stark-small-icon"
[matTooltip]="'STARK.TABLE.MULTI_COLUMN_SORTING' | translate"
starkSvgViewBox
svgIcon="sort"
></mat-icon>
</button>

<ng-container *ngIf="filter.globalFilterPresent">
<button [matMenuTriggerFor]="globalFilter" mat-icon-button>
<mat-icon [matTooltip]="'STARK.TABLE.FILTER' | translate" class="stark-small-icon" starkSvgViewBox svgIcon="filter"></mat-icon>
</button>
<mat-menu class="mat-table-filter" #globalFilter="matMenu" xPosition="before" [overlapTrigger]="false">
<div>
<mat-form-field (click)="$event.stopPropagation()" (keyup)="$event.stopPropagation()" (keydown)="$event.stopPropagation()">
<input
matInput
id="{{ htmlId + '-' + 'table-filter' }}"
[placeholder]="'STARK.TABLE.GLOBAL_FILTER' | translate"
name="global-filter"
[formControl]="_globalFilterFormCtrl"
/>
</mat-form-field>
<button mat-icon-button (click)="onClearFilter()">
<mat-icon
class="stark-small-icon"
starkSvgViewBox
svgIcon="close"
[matTooltip]="'STARK.TABLE.CLEAR_FILTER' | translate"
></mat-icon>
</button>
</div>
</mat-menu>
</ng-container>

<stark-minimap
[matTooltip]="'STARK.TABLE.TOGGLE_COLUMNS' | translate"
*ngIf="minimap !== false"
[mode]="minimap === 'compact' ? 'compact' : undefined"
[items]="_minimapItemProperties"
[visibleItems]="_visibleMinimapItems"
(showHideItem)="toggleColumnVisibility($event)"
></stark-minimap>
</ng-template>

<div class="header">
<div class="transcluded">
<ng-content select="header"></ng-content>
</div>

<div class="actions" [ngClass]="{ 'actions-alt': customTableActionsType === 'alt' }">
<div class="actions">
<ng-container *ngIf="customTableActionsType === 'alt'">
<ng-container *ngTemplateOutlet="tableActions"></ng-container>
</ng-container>

<stark-action-bar
[actionBarConfig]="customTableRegularActions"
[alternativeActions]="customTableAltActions"
buttonColor="alt"
mode="compact"
></stark-action-bar>

<stark-pagination htmlSuffixId="{{ htmlId }}-pagination" [paginationConfig]="paginationConfig" mode="compact"></stark-pagination>

<button *ngIf="isMultiSortEnabled" (click)="openMultiSortDialog()" mat-icon-button>
<mat-icon
class="stark-small-icon"
[matTooltip]="'STARK.TABLE.MULTI_COLUMN_SORTING' | translate"
starkSvgViewBox
svgIcon="sort"
></mat-icon>
</button>

<ng-container *ngIf="filter.globalFilterPresent">
<button [matMenuTriggerFor]="globalFilter" mat-icon-button>
<mat-icon
[matTooltip]="'STARK.TABLE.FILTER' | translate"
class="stark-small-icon"
starkSvgViewBox
svgIcon="filter"
></mat-icon>
</button>
<mat-menu class="mat-table-filter" #globalFilter="matMenu" xPosition="before" [overlapTrigger]="false">
<div>
<mat-form-field
(click)="$event.stopPropagation()"
(keyup)="$event.stopPropagation()"
(keydown)="$event.stopPropagation()"
>
<input
matInput
id="{{ htmlId + '-' + 'table-filter' }}"
[placeholder]="'STARK.TABLE.GLOBAL_FILTER' | translate"
name="global-filter"
[formControl]="_globalFilterFormCtrl"
/>
</mat-form-field>
<button mat-icon-button (click)="onClearFilter()">
<mat-icon
class="stark-small-icon"
starkSvgViewBox
svgIcon="close"
[matTooltip]="'STARK.TABLE.CLEAR_FILTER' | translate"
></mat-icon>
</button>
</div>
</mat-menu>
<ng-container *ngIf="customTableActionsType !== 'alt'">
<ng-container *ngTemplateOutlet="tableActions"></ng-container>
</ng-container>

<stark-minimap
[matTooltip]="'STARK.TABLE.TOGGLE_COLUMNS' | translate"
*ngIf="minimap !== false"
[mode]="minimap === 'compact' ? 'compact' : undefined"
[items]="_minimapItemProperties"
[visibleItems]="_visibleMinimapItems"
(showHideItem)="toggleColumnVisibility($event)"
></stark-minimap>
</div>
</div>

Expand Down
113 changes: 99 additions & 14 deletions packages/stark-ui/src/modules/table/components/table.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import createSpy = jasmine.createSpy;
[multiSelect]="multiSelect"
[orderProperties]="orderProperties"
[tableRowActions]="tableRowActions"
[showRowsCounter]="showRowsCounter"
[rowClassNameFn]="rowClassNameFn"
(rowClicked)="rowClickHandler($event)"
>
Expand All @@ -54,6 +55,7 @@ class TestHostComponent {
public rowsSelectable?: boolean;
public multiSelect?: string;
public multiSort?: string;
public showRowsCounter?: boolean;
public tableRowActions?: StarkTableRowActions;
public tableFilter?: StarkTableFilter;
public orderProperties?: string[];
Expand Down Expand Up @@ -151,6 +153,7 @@ describe("TableComponent", () => {
expect(component.multiSelect).toBe(hostComponent.multiSelect);
expect(component.multiSort).toBe(hostComponent.multiSort);
expect(component.orderProperties).toBe(hostComponent.orderProperties);
expect(component.showRowsCounter).toBe(false);
expect(component.tableRowActions).toBe(<any>hostComponent.tableRowActions);
});
});
Expand All @@ -164,7 +167,7 @@ describe("TableComponent", () => {
expect(component.dataSource.data).toEqual(dummyData);
expect(component.dataSource.data).not.toBe(component.data);
});

it("should trigger resetFilterValueOnDataChange and sortData methods when data changes", () => {
spyOn(component, "resetFilterValueOnDataChange");
spyOn(component, "sortData");
Expand Down Expand Up @@ -254,6 +257,25 @@ describe("TableComponent", () => {
expect(component.sortData).toHaveBeenCalledTimes(1);
expect(component.orderProperties).toEqual(["test"]);
});

it("should display/hide the counter element when 'showRowsCounter' changes", () => {
const rowsCounterSelector = ".stark-table-rows-counter";
hostComponent.dummyData = [{ name: "dummy-data-1" }, { name: "dummy-data-2" }, { name: "dummy-data-3" }, { name: "dummy-data-4" }];
hostFixture.detectChanges();

let rowsCounterElement = hostFixture.debugElement.nativeElement.querySelector(rowsCounterSelector);
expect(rowsCounterElement).toBeNull();
expect(component.showRowsCounter).toBe(false);

hostComponent.showRowsCounter = true;
hostFixture.detectChanges();
expect(component.showRowsCounter).toBe(true);
rowsCounterElement = hostFixture.debugElement.nativeElement.querySelector(rowsCounterSelector);
expect(rowsCounterElement).toBeTruthy();
const rowsCounterNumberElement = (<HTMLElement>rowsCounterElement).querySelector("span");
expect(rowsCounterNumberElement).toBeTruthy();
expect((<HTMLElement>rowsCounterNumberElement).innerText).toContain("4");
});
});

describe("sortData", () => {
Expand All @@ -274,7 +296,16 @@ describe("TableComponent", () => {

component.sortData();

expect(component.dataSource.data).toEqual([{ a: 1 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }, { a: 10 }, { a: 20 }]);
expect(component.dataSource.data).toEqual([
{ a: 1 },
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ a: 4 },
{ a: 5 },
{ a: 10 },
{ a: 20 }
]);
});

it("should sort data descending", () => {
Expand All @@ -285,7 +316,16 @@ describe("TableComponent", () => {

component.sortData();

expect(component.dataSource.data).toEqual([{ a: 20 }, { a: 10 }, { a: 5 }, { a: 4 }, { a: 3 }, { a: 2 }, { a: 1 }, { a: 1 }]);
expect(component.dataSource.data).toEqual([
{ a: 20 },
{ a: 10 },
{ a: 5 },
{ a: 4 },
{ a: 3 },
{ a: 2 },
{ a: 1 },
{ a: 1 }
]);
});

it("should sort data descending column A then ascending column B", () => {
Expand Down Expand Up @@ -371,40 +411,85 @@ describe("TableComponent", () => {

component.sortData();

expect(component.dataSource.data).toEqual([{ a: 1 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }, { a: 10 }, { a: 20 }]);
expect(component.dataSource.data).toEqual([
{ a: 1 },
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ a: 4 },
{ a: 5 },
{ a: 10 },
{ a: 20 }
]);
expect(hostComponent.columnProperties[0].compareFn).toHaveBeenCalled();
// Due to browsers, we cannot predict exactly the number of calls. On IE, it is 9 times, on Chrome it can be 7, 8 or 14 times depending on the version
// Due to browsers, we cannot predict exactly the number of calls. On IE, it is 9 times, on Chrome it can be 7, 8 or 14 times depending on the version
expect((<Spy>hostComponent.columnProperties[0].compareFn).calls.count()).toBeGreaterThanOrEqual(7);
expect((<Spy>hostComponent.columnProperties[0].compareFn).calls.count()).toBeLessThanOrEqual(14);
});

it("should sort data when click on the column", () => {
expect(component.dataSource.data).toEqual([{ a: 1 }, { a: 1 }, { a: 3 }, { a: 2 }, { a: 4 }, { a: 5 }, { a: 10 }, { a: 20 }]);

expect(component.dataSource.data).toEqual([
{ a: 1 },
{ a: 1 },
{ a: 3 },
{ a: 2 },
{ a: 4 },
{ a: 5 },
{ a: 10 },
{ a: 20 }
]);

const column: HTMLElement = hostFixture.debugElement.nativeElement.querySelector(getColumnSelector("a"));
column.click();
hostFixture.detectChanges();
expect(component.dataSource.data).toEqual([{ a: 1 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }, { a: 10 }, { a: 20 }]);
expect(component.dataSource.data).toEqual([
{ a: 1 },
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ a: 4 },
{ a: 5 },
{ a: 10 },
{ a: 20 }
]);

column.click();
hostFixture.detectChanges();
expect(component.dataSource.data).toEqual([{ a: 20 }, { a: 10 }, { a: 5 }, { a: 4 }, { a: 3 }, { a: 2 }, { a: 1 }, { a: 1 }]);
expect(component.dataSource.data).toEqual([
{ a: 20 },
{ a: 10 },
{ a: 5 },
{ a: 4 },
{ a: 3 },
{ a: 2 },
{ a: 1 },
{ a: 1 }
]);

column.click();
hostFixture.detectChanges();
expect(component.dataSource.data).toEqual([{ a: 1 }, { a: 1 }, { a: 3 }, { a: 2 }, { a: 4 }, { a: 5 }, { a: 10 }, { a: 20 }]);
expect(component.dataSource.data).toEqual([
{ a: 1 },
{ a: 1 },
{ a: 3 },
{ a: 2 },
{ a: 4 },
{ a: 5 },
{ a: 10 },
{ a: 20 }
]);
});

it("should sort data when click on different columns", () => {
hostComponent.dummyData = [{ a: 2, b: 3, c: 1 }, { a: 1, b: 2, c: 3 }, { a: 3, b: 1, c: 2 }];
hostComponent.columnProperties = [{ name: "a" }, { name: "b" }, { name: "c" }];
hostFixture.detectChanges();
expect(component.dataSource.data).toEqual(hostComponent.dummyData);

const columnA: HTMLElement = hostFixture.debugElement.nativeElement.querySelector(getColumnSelector("a"));
const columnB: HTMLElement = hostFixture.debugElement.nativeElement.querySelector(getColumnSelector("b"));
const columnC: HTMLElement = hostFixture.debugElement.nativeElement.querySelector(getColumnSelector("c"));

columnA.click();
expect(component.dataSource.data).toEqual([{ a: 1, b: 2, c: 3 }, { a: 2, b: 3, c: 1 }, { a: 3, b: 1, c: 2 }]);
columnA.click();
Expand All @@ -414,7 +499,7 @@ describe("TableComponent", () => {
expect(component.dataSource.data).toEqual([{ a: 3, b: 1, c: 2 }, { a: 1, b: 2, c: 3 }, { a: 2, b: 3, c: 1 }]);
columnB.click();
expect(component.dataSource.data).toEqual([{ a: 2, b: 3, c: 1 }, { a: 1, b: 2, c: 3 }, { a: 3, b: 1, c: 2 }]);

columnC.click();
expect(component.dataSource.data).toEqual([{ a: 2, b: 3, c: 1 }, { a: 3, b: 1, c: 2 }, { a: 1, b: 2, c: 3 }]);
columnC.click();
Expand Down Expand Up @@ -574,7 +659,7 @@ describe("TableComponent", () => {
{ a: { b: 7 } }
]);
expect(hostComponent.columnProperties[0].compareFn).toHaveBeenCalled();
// Due to browsers, we cannot predict exactly the number of calls. On IE, it is 9 times, on Chrome it can be 7, 8 or 14 times depending on the version
// Due to browsers, we cannot predict exactly the number of calls. On IE, it is 9 times, on Chrome it can be 7, 8 or 14 times depending on the version
expect((<Spy>hostComponent.columnProperties[0].compareFn).calls.count()).toBeGreaterThanOrEqual(7);
expect((<Spy>hostComponent.columnProperties[0].compareFn).calls.count()).toBeLessThanOrEqual(14);
});
Expand Down
Loading

0 comments on commit 0d983a6

Please sign in to comment.