From 50e7e6b536fa7d4ef4e7a08962788c945388a59e Mon Sep 17 00:00:00 2001 From: Benedikt Langer Date: Thu, 11 Feb 2021 08:22:16 +0100 Subject: [PATCH 1/2] feat: table sort --- .../table/src/data/table-data-source.ts | 6 +- .../src/services/table-settings.service.ts | 2 +- .../subcomponents/table-data.component.html | 209 ++++++++++-------- .../src/subcomponents/table-data.component.ts | 188 ++++++++-------- .../subcomponents/table-header.component.ts | 195 ++++++++-------- .../subcomponents/table-settings.component.ts | 11 +- .../src/subcomponents/table-sort.component.ts | 183 +++++++-------- .../components/table/src/table.component.html | 5 +- .../components/table/src/table.component.ts | 36 +-- projects/components/table/src/table.module.ts | 181 +++++++-------- 10 files changed, 528 insertions(+), 488 deletions(-) diff --git a/projects/components/table/src/data/table-data-source.ts b/projects/components/table/src/data/table-data-source.ts index 821970ec..d3aa8507 100644 --- a/projects/components/table/src/data/table-data-source.ts +++ b/projects/components/table/src/data/table-data-source.ts @@ -64,7 +64,7 @@ export class PsTableDataSource extends DataSource { public sortColumn: string = null; /** The sort direction. Defaulted to asc. */ - public sortDirection: 'asc' | 'desc' = 'asc'; + public sortDirection: 'asc' | 'desc' | null = 'asc'; /** The zero-based page index of the displayed list of items. Defaulted to 0. */ public pageIndex = 0; @@ -275,7 +275,7 @@ export class PsTableDataSource extends DataSource { currentPage: this.pageIndex, searchText: this.filter, sortColumn: this.sortColumn, - sortDirection: this.sortDirection, + sortDirection: this.sortDirection || null, }; if (extended) { (data as IExtendedPsTableUpdateDataInfo).triggerData = this._lastLoadTriggerData; @@ -417,7 +417,7 @@ export class PsTableDataSource extends DataSource { return this.sortData(data.slice(), { sortColumn: this.sortColumn, - sortDirection: this.sortDirection, + sortDirection: this.sortDirection || null, }); } diff --git a/projects/components/table/src/services/table-settings.service.ts b/projects/components/table/src/services/table-settings.service.ts index f2989a48..0e1093c5 100644 --- a/projects/components/table/src/services/table-settings.service.ts +++ b/projects/components/table/src/services/table-settings.service.ts @@ -4,7 +4,7 @@ import { EMPTY, Observable, of } from 'rxjs'; export interface IPsTableSetting { columnBlacklist: string[]; sortColumn: string; - sortDirection: 'asc' | 'desc'; + sortDirection: 'asc' | 'desc' | null; pageSize: number; } diff --git a/projects/components/table/src/subcomponents/table-data.component.html b/projects/components/table/src/subcomponents/table-data.component.html index 6853cb23..3cd5e196 100644 --- a/projects/components/table/src/subcomponents/table-data.component.html +++ b/projects/components/table/src/subcomponents/table-data.component.html @@ -1,96 +1,113 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - {{ columnDef.header }} - - - - - {{ element[columnDef.property] }} - - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + {{ columnDef.header }} + + + + + {{ element[columnDef.property] }} + + + + + + + + + + + + + + + + + + + + +
diff --git a/projects/components/table/src/subcomponents/table-data.component.ts b/projects/components/table/src/subcomponents/table-data.component.ts index 475a85d6..dea7d1db 100644 --- a/projects/components/table/src/subcomponents/table-data.component.ts +++ b/projects/components/table/src/subcomponents/table-data.component.ts @@ -1,90 +1,98 @@ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - Output, - TemplateRef, - ViewEncapsulation, - SimpleChanges, - OnChanges, -} from '@angular/core'; -import { IPsTableIntlTexts } from '@prosoft/components/core'; -import { PsTableDataSource } from '../data/table-data-source'; -import { PsTableColumnDirective, PsTableRowDetailDirective } from '../directives/table.directives'; -import { Subscription } from 'rxjs'; - -@Component({ - selector: 'ps-table-data', - templateUrl: './table-data.component.html', - styleUrls: ['./table-data.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, -}) -export class PsTableDataComponent implements OnChanges { - @Input() public dataSource: PsTableDataSource<{ [key: string]: any }>; - @Input() public tableId: string; - @Input() public intl: IPsTableIntlTexts; - @Input() public rowActions: TemplateRef | null = null; - @Input() public rowDetail: PsTableRowDetailDirective | null; - @Input() public listActions: TemplateRef | null = null; - @Input() public columnDefs: PsTableColumnDirective[]; - @Input() public showListActions: boolean; - @Input() public refreshable: boolean; - @Input() public settingsEnabled: boolean; - @Input() public displayedColumns: string[]; - - @Output() public showSettingsClicked = new EventEmitter(); - @Output() public refreshDataClicked = new EventEmitter(); - - private _dataSourceChangesSub = Subscription.EMPTY; - - constructor(private cd: ChangeDetectorRef) {} - - public ngOnChanges(changes: SimpleChanges) { - if (changes.dataSource) { - this._dataSourceChangesSub.unsubscribe(); - this._dataSourceChangesSub = this.dataSource._internalDetectChanges.subscribe(() => { - this.cd.markForCheck(); - }); - } - } - - public onShowSettingsClicked() { - this.showSettingsClicked.emit(); - } - - public onRefreshDataClicked() { - this.refreshDataClicked.emit(); - } - - public toggleRowDetail(item: { [key: string]: any }) { - this.rowDetail.toggle(item); - this.cd.markForCheck(); - } - - public onMasterToggleChange() { - this.dataSource.toggleVisibleRowSelection(); - } - - public onRowToggleChange(row: any) { - this.dataSource.selectionModel.toggle(row); - } - - public isMasterToggleChecked() { - return this.dataSource.selectionModel.hasValue() && this.dataSource.allVisibleRowsSelected; - } - - public isMasterToggleIndeterminate() { - return this.dataSource.selectionModel.hasValue() && !this.dataSource.allVisibleRowsSelected; - } - - public isRowSelected(row: any) { - return this.dataSource.selectionModel.isSelected(row); - } - - public getSelectedRows() { - return this.dataSource.selectionModel.selected; - } -} +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + Output, + TemplateRef, + ViewEncapsulation, + SimpleChanges, + OnChanges, +} from '@angular/core'; +import { IPsTableIntlTexts } from '@prosoft/components/core'; +import { PsTableDataSource } from '../data/table-data-source'; +import { PsTableColumnDirective, PsTableRowDetailDirective } from '../directives/table.directives'; +import { Subscription } from 'rxjs'; +import { Sort } from '@angular/material/sort'; + +@Component({ + selector: 'ps-table-data', + templateUrl: './table-data.component.html', + styleUrls: ['./table-data.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class PsTableDataComponent implements OnChanges { + @Input() public dataSource: PsTableDataSource<{ [key: string]: any }>; + @Input() public tableId: string; + @Input() public intl: IPsTableIntlTexts; + @Input() public rowActions: TemplateRef | null = null; + @Input() public rowDetail: PsTableRowDetailDirective | null; + @Input() public listActions: TemplateRef | null = null; + @Input() public columnDefs: PsTableColumnDirective[]; + @Input() public showListActions: boolean; + @Input() public refreshable: boolean; + @Input() public settingsEnabled: boolean; + @Input() public displayedColumns: string[]; + @Input() public sortColumn: string; + @Input() public sortDirection: 'asc' | 'desc' | null; + + @Output() public showSettingsClicked = new EventEmitter(); + @Output() public refreshDataClicked = new EventEmitter(); + @Output() public sortChanged = new EventEmitter(); + + private _dataSourceChangesSub = Subscription.EMPTY; + + constructor(private cd: ChangeDetectorRef) {} + + public ngOnChanges(changes: SimpleChanges) { + if (changes.dataSource) { + this._dataSourceChangesSub.unsubscribe(); + this._dataSourceChangesSub = this.dataSource._internalDetectChanges.subscribe(() => { + this.cd.markForCheck(); + }); + } + } + + public onShowSettingsClicked() { + this.showSettingsClicked.emit(); + } + + public onRefreshDataClicked() { + this.refreshDataClicked.emit(); + } + + public onSortChanged(sort: Sort) { + this.sortChanged.emit(sort); + } + + public toggleRowDetail(item: { [key: string]: any }) { + this.rowDetail.toggle(item); + this.cd.markForCheck(); + } + + public onMasterToggleChange() { + this.dataSource.toggleVisibleRowSelection(); + } + + public onRowToggleChange(row: any) { + this.dataSource.selectionModel.toggle(row); + } + + public isMasterToggleChecked() { + return this.dataSource.selectionModel.hasValue() && this.dataSource.allVisibleRowsSelected; + } + + public isMasterToggleIndeterminate() { + return this.dataSource.selectionModel.hasValue() && !this.dataSource.allVisibleRowsSelected; + } + + public isRowSelected(row: any) { + return this.dataSource.selectionModel.isSelected(row); + } + + public getSelectedRows() { + return this.dataSource.selectionModel.selected; + } +} diff --git a/projects/components/table/src/subcomponents/table-header.component.ts b/projects/components/table/src/subcomponents/table-header.component.ts index 130f549a..6d1eac9a 100644 --- a/projects/components/table/src/subcomponents/table-header.component.ts +++ b/projects/components/table/src/subcomponents/table-header.component.ts @@ -1,97 +1,98 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - Output, - TemplateRef, - ViewEncapsulation, - HostBinding, -} from '@angular/core'; -import { IPsTableIntlTexts } from '@prosoft/components/core'; -import { IPsTableSortDefinition } from '../models'; - -@Component({ - selector: 'ps-table-header', - template: ` -

{{ caption }}

- - - -
- -
- `, - styles: [ - ` - ps-table-header { - padding: 0 16px; - - display: flex; - flex-wrap: wrap; - align-items: flex-end; - justify-content: space-between; - } - - .ps-table-header__caption { - flex-basis: 100%; - } - - .ps-table-header__sort { - flex: 0 1 350px; - margin-right: auto; /* This counters the margin of the actions to push the search back to the middle */ - } - - .ps-table-header__search { - flex: 0 1 800px; - } - - .ps-table-header__actions { - flex-basis: auto; - margin: 0.3em 8px 1em; - text-align: end; - align-self: flex-end; - margin-left: auto; /* This ensures that the actions are always right, even if there is no other flex item */ - } - `, - ], - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, -}) -export class PsTableHeaderComponent { - @Input() public intl: IPsTableIntlTexts; - @Input() public caption: string; - @Input() public topButtonSection: TemplateRef | null; - @Input() public customHeader: TemplateRef | null; - @Input() public selectedRows: any[]; - - @Input() public showSorting: boolean; - @Input() public sortColumn: string; - @Input() public sortDirection: 'asc' | 'desc'; - @Input() public sortDefinitions: IPsTableSortDefinition[] = []; - - @Input() public filterable: boolean; - @Input() public searchText: string; - - @Output() public sortChanged = new EventEmitter<{ sortColumn: string; sortDirection: 'asc' | 'desc' }>(); - @Output() public searchChanged = new EventEmitter(); - - @HostBinding('style.padding-top') public get paddingTop() { - return !this.caption && (this.showSorting || this.filterable || this.topButtonSection) ? '1em' : '0'; - } -} +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, + TemplateRef, + ViewEncapsulation, + HostBinding, +} from '@angular/core'; +import { Sort } from '@angular/material/sort'; +import { IPsTableIntlTexts } from '@prosoft/components/core'; +import { IPsTableSortDefinition } from '../models'; + +@Component({ + selector: 'ps-table-header', + template: ` +

{{ caption }}

+ + + +
+ +
+ `, + styles: [ + ` + ps-table-header { + padding: 0 16px; + + display: flex; + flex-wrap: wrap; + align-items: flex-end; + justify-content: space-between; + } + + .ps-table-header__caption { + flex-basis: 100%; + } + + .ps-table-header__sort { + flex: 0 1 350px; + margin-right: auto; /* This counters the margin of the actions to push the search back to the middle */ + } + + .ps-table-header__search { + flex: 0 1 800px; + } + + .ps-table-header__actions { + flex-basis: auto; + margin: 0.3em 8px 1em; + text-align: end; + align-self: flex-end; + margin-left: auto; /* This ensures that the actions are always right, even if there is no other flex item */ + } + `, + ], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class PsTableHeaderComponent { + @Input() public intl: IPsTableIntlTexts; + @Input() public caption: string; + @Input() public topButtonSection: TemplateRef | null; + @Input() public customHeader: TemplateRef | null; + @Input() public selectedRows: any[]; + + @Input() public showSorting: boolean; + @Input() public sortColumn: string; + @Input() public sortDirection: 'asc' | 'desc' | null; + @Input() public sortDefinitions: IPsTableSortDefinition[] = []; + + @Input() public filterable: boolean; + @Input() public searchText: string; + + @Output() public sortChanged = new EventEmitter(); + @Output() public searchChanged = new EventEmitter(); + + @HostBinding('style.padding-top') public get paddingTop() { + return !this.caption && (this.showSorting || this.filterable || this.topButtonSection) ? '1em' : '0'; + } +} diff --git a/projects/components/table/src/subcomponents/table-settings.component.ts b/projects/components/table/src/subcomponents/table-settings.component.ts index 508cfacd..5b38aadf 100644 --- a/projects/components/table/src/subcomponents/table-settings.component.ts +++ b/projects/components/table/src/subcomponents/table-settings.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core'; import { MatCheckboxChange } from '@angular/material/checkbox'; +import { Sort } from '@angular/material/sort'; import { IPsTableIntlTexts } from '@prosoft/components/core'; import { Observable, Subscription } from 'rxjs'; import { first, map } from 'rxjs/operators'; @@ -63,12 +64,12 @@ export class PsTableSettingsComponent implements OnInit { return !settings.columnBlacklist.some((x) => x === columnDef.property); } - public onSortChanged(event: { sortColumn: string; sortDirection: 'asc' | 'desc' }, settings: IPsTableSetting) { - if (settings.sortColumn !== event.sortColumn) { - settings.sortColumn = event.sortColumn; - settings.columnBlacklist = settings.columnBlacklist.filter((x) => x !== event.sortColumn); + public onSortChanged(event: Sort, settings: IPsTableSetting) { + if (settings.sortColumn !== event.active) { + settings.sortColumn = event.active; + settings.columnBlacklist = settings.columnBlacklist.filter((x) => x !== event.active); } - settings.sortDirection = event.sortDirection; + settings.sortDirection = event.direction || null; } public onColumnVisibilityChange(event: MatCheckboxChange, settings: IPsTableSetting, columnDef: PsTableColumnDirective) { diff --git a/projects/components/table/src/subcomponents/table-sort.component.ts b/projects/components/table/src/subcomponents/table-sort.component.ts index a3a43f75..ed893a59 100644 --- a/projects/components/table/src/subcomponents/table-sort.component.ts +++ b/projects/components/table/src/subcomponents/table-sort.component.ts @@ -1,91 +1,92 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; -import { MatSelectChange } from '@angular/material/select'; -import { IPsTableIntlTexts } from '@prosoft/components/core'; -import { IPsTableSortDefinition } from '../models'; - -@Component({ - selector: 'ps-table-sort', - template: ` - - {{ intl.sortLabel }} - - {{ - sortDefinition.displayName - }} - - - - - `, - styles: [ - ` - ps-table-sort { - display: grid; - grid-template-columns: 1fr min-content min-content; - } - - .ps-table-sort__dir-button { - width: 28px; - height: 28px; - line-height: 28px; - margin-top: 16px; - margin-left: 0.2em; - } - - .ps-table-sort__dir-button .mat-button-wrapper { - padding: 0; - } - - .ps-table-sort__dir-button--inactive { - background-color: transparent !important; - color: black !important; - } - `, - ], - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, -}) -export class PsTableSortComponent { - @Input() public intl: IPsTableIntlTexts; - @Input() public sortColumn: string; - @Input() public sortDirection: 'asc' | 'desc'; - @Input() public sortDefinitions: IPsTableSortDefinition[] = []; - @Output() public sortChanged = new EventEmitter<{ sortColumn: string; sortDirection: 'asc' | 'desc' }>(); - - public onSortColumnChange(event: MatSelectChange) { - if (this.sortColumn !== event.value) { - this.sortColumn = event.value; - this.emitChange(); - } - } - - public onSortSirectionChange(dir: 'asc' | 'desc') { - if (this.sortDirection !== dir) { - this.sortDirection = dir; - this.emitChange(); - } - } - - private emitChange() { - this.sortChanged.emit({ - sortColumn: this.sortColumn, - sortDirection: this.sortDirection, - }); - } -} +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; +import { MatSelectChange } from '@angular/material/select'; +import { Sort } from '@angular/material/sort'; +import { IPsTableIntlTexts } from '@prosoft/components/core'; +import { IPsTableSortDefinition } from '../models'; + +@Component({ + selector: 'ps-table-sort', + template: ` + + {{ intl.sortLabel }} + + {{ + sortDefinition.displayName + }} + + + + + `, + styles: [ + ` + ps-table-sort { + display: grid; + grid-template-columns: 1fr min-content min-content; + } + + .ps-table-sort__dir-button { + width: 28px; + height: 28px; + line-height: 28px; + margin-top: 16px; + margin-left: 0.2em; + } + + .ps-table-sort__dir-button .mat-button-wrapper { + padding: 0; + } + + .ps-table-sort__dir-button--inactive { + background-color: transparent !important; + color: black !important; + } + `, + ], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class PsTableSortComponent { + @Input() public intl: IPsTableIntlTexts; + @Input() public sortColumn: string; + @Input() public sortDirection: 'asc' | 'desc' | null; + @Input() public sortDefinitions: IPsTableSortDefinition[] = []; + @Output() public sortChanged = new EventEmitter(); + + public onSortColumnChange(event: MatSelectChange) { + if (this.sortColumn !== event.value) { + this.sortColumn = event.value; + this.emitChange(); + } + } + + public onSortSirectionChange(dir: 'asc' | 'desc') { + if (this.sortDirection !== dir) { + this.sortDirection = dir; + this.emitChange(); + } + } + + private emitChange() { + this.sortChanged.emit({ + active: this.sortColumn, + direction: this.sortDirection, + }); + } +} diff --git a/projects/components/table/src/table.component.html b/projects/components/table/src/table.component.html index dfc499cd..f16bc3d3 100644 --- a/projects/components/table/src/table.component.html +++ b/projects/components/table/src/table.component.html @@ -1,4 +1,4 @@ - +
{{ intl.noEntriesLabel }}
diff --git a/projects/components/table/src/table.component.ts b/projects/components/table/src/table.component.ts index 6b59471a..4f6b7d76 100644 --- a/projects/components/table/src/table.component.ts +++ b/projects/components/table/src/table.component.ts @@ -39,6 +39,7 @@ import { import { PsTableStateManager, PsTableUrlStateManager } from './helper/state-manager'; import { IPsTableSortDefinition, IPsTableUpdateDataInfo } from './models'; import { IPsTableSetting, PsTableSettingsService } from './services/table-settings.service'; +import { Sort } from '@angular/material/sort'; @Component({ selector: 'ps-table', @@ -82,6 +83,7 @@ export class PsTableComponent implements OnInit, OnChanges, AfterContentInit, On @Input() stateManager: PsTableStateManager = new PsTableUrlStateManager(this.router, this.route); + /** @deprecated use the datasource to detect paginations */ @Output() public page = new EventEmitter(); @ViewChild(PsFlipContainerComponent, { static: true }) public flipContainer: PsFlipContainerComponent | null = null; @@ -159,10 +161,10 @@ export class PsTableComponent implements OnInit, OnChanges, AfterContentInit, On public displayedColumns: string[] = []; - public get sortDirection(): 'asc' | 'desc' { + public get sortDirection(): 'asc' | 'desc' | null { return this.dataSource.sortDirection; } - public set sortDirection(value: 'asc' | 'desc') { + public set sortDirection(value: 'asc' | 'desc' | null) { this.dataSource.sortDirection = value; } @@ -279,21 +281,24 @@ export class PsTableComponent implements OnInit, OnChanges, AfterContentInit, On } public onSearchChanged(value: string) { - this.filterText = value; - this.requestUpdate(); + this.requestUpdate({ + searchText: value, + }); } - public onSortChanged(event: { sortColumn: string; sortDirection: 'asc' | 'desc' }) { - this.sortColumn = event.sortColumn; - this.sortDirection = event.sortDirection; - this.requestUpdate(); + public onSortChanged(event: Sort) { + this.requestUpdate({ + sortColumn: event.active, + sortDirection: event.direction || null, + }); } public onPage(event: PageEvent) { - this.pageIndex = event.pageIndex; - this.pageSize = event.pageSize; this.page.emit(event); - this.requestUpdate(); + this.requestUpdate({ + currentPage: event.pageIndex, + pageSize: event.pageSize, + }); } public onRefreshDataClicked() { @@ -313,8 +318,11 @@ export class PsTableComponent implements OnInit, OnChanges, AfterContentInit, On this.rowDetail.toggle(item, open); } - private requestUpdate() { - const updateInfo = this.dataSource.getUpdateDataInfo(); + private requestUpdate(data: Partial) { + const updateInfo = { + ...this.dataSource.getUpdateDataInfo(), + ...data, + }; this.stateManager.requestUpdate(this.tableId, updateInfo); } @@ -352,7 +360,7 @@ export class PsTableComponent implements OnInit, OnChanges, AfterContentInit, On this.pageIndex = Math.max(urlSettings.currentPage || 0, 0); this.pageSize = Math.max(urlSettings.pageSize || tableSettings.pageSize || 15, 1); this.sortColumn = urlSettings.sortColumn || tableSettings.sortColumn || null; - this.sortDirection = urlSettings.sortDirection || tableSettings.sortDirection || 'asc'; + this.sortDirection = urlSettings.sortDirection || tableSettings.sortDirection || null; this.filterText = urlSettings.searchText || ''; this.displayedColumns = this.columnDefs.map((x) => x.property); diff --git a/projects/components/table/src/table.module.ts b/projects/components/table/src/table.module.ts index 0123e546..da075049 100644 --- a/projects/components/table/src/table.module.ts +++ b/projects/components/table/src/table.module.ts @@ -1,90 +1,91 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSelectModule } from '@angular/material/select'; -import { MatSortModule } from '@angular/material/sort'; -import { MatTableModule } from '@angular/material/table'; -import { PsFlipContainerModule } from '@prosoft/components/flip-container'; -import { PsSavebarModule } from '@prosoft/components/savebar'; -import { - PsTableColumnDirective, - PsTableColumnHeaderTemplateDirective, - PsTableColumnTemplateDirective, - PsTableCustomHeaderDirective, - PsTableCustomSettingsDirective, - PsTableListActionsDirective, - PsTableRowActionsDirective, - PsTableRowDetailDirective, - PsTableRowDetailTemplateDirective, - PsTableTopButtonSectionDirective, -} from './directives/table.directives'; -import { PsTableDataComponent } from './subcomponents/table-data.component'; -import { PsTableHeaderComponent } from './subcomponents/table-header.component'; -import { PsTablePaginationComponent } from './subcomponents/table-pagination.component'; -import { TableRowDetailComponent } from './subcomponents/table-row-detail.component'; -import { PsTableSearchComponent } from './subcomponents/table-search.component'; -import { PsTableSettingsComponent } from './subcomponents/table-settings.component'; -import { PsTableSortComponent } from './subcomponents/table-sort.component'; -import { PsTableComponent } from './table.component'; - -@NgModule({ - declarations: [ - PsTableComponent, - PsTableDataComponent, - PsTableSettingsComponent, - PsTableHeaderComponent, - PsTableSortComponent, - PsTableSearchComponent, - TableRowDetailComponent, - PsTablePaginationComponent, - PsTableColumnDirective, - PsTableColumnTemplateDirective, - PsTableColumnHeaderTemplateDirective, - PsTableTopButtonSectionDirective, - PsTableListActionsDirective, - PsTableRowActionsDirective, - PsTableCustomHeaderDirective, - PsTableRowDetailDirective, - PsTableRowDetailTemplateDirective, - PsTableCustomSettingsDirective, - ], - imports: [ - CommonModule, - FormsModule, - MatSortModule, - MatTableModule, - MatPaginatorModule, - MatCheckboxModule, - MatIconModule, - MatButtonModule, - MatMenuModule, - MatSelectModule, - MatInputModule, - MatCardModule, - MatProgressSpinnerModule, - PsFlipContainerModule, - PsSavebarModule, - ], - exports: [ - PsTableComponent, - PsTableColumnDirective, - PsTableColumnTemplateDirective, - PsTableColumnHeaderTemplateDirective, - PsTableTopButtonSectionDirective, - PsTableListActionsDirective, - PsTableRowActionsDirective, - PsTableCustomHeaderDirective, - PsTableRowDetailDirective, - PsTableRowDetailTemplateDirective, - PsTableCustomSettingsDirective, - ], -}) -export class PsTableModule {} +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; +import { PsFlipContainerModule } from '@prosoft/components/flip-container'; +import { PsSavebarModule } from '@prosoft/components/savebar'; +import { + PsTableColumnDirective, + PsTableColumnHeaderTemplateDirective, + PsTableColumnTemplateDirective, + PsTableCustomHeaderDirective, + PsTableCustomSettingsDirective, + PsTableListActionsDirective, + PsTableRowActionsDirective, + PsTableRowDetailDirective, + PsTableRowDetailTemplateDirective, + PsTableTopButtonSectionDirective, +} from './directives/table.directives'; +import { PsTableDataComponent } from './subcomponents/table-data.component'; +import { PsTableHeaderComponent } from './subcomponents/table-header.component'; +import { PsTablePaginationComponent } from './subcomponents/table-pagination.component'; +import { TableRowDetailComponent } from './subcomponents/table-row-detail.component'; +import { PsTableSearchComponent } from './subcomponents/table-search.component'; +import { PsTableSettingsComponent } from './subcomponents/table-settings.component'; +import { PsTableSortComponent } from './subcomponents/table-sort.component'; +import { PsTableComponent } from './table.component'; + +@NgModule({ + declarations: [ + PsTableComponent, + PsTableDataComponent, + PsTableSettingsComponent, + PsTableHeaderComponent, + PsTableSortComponent, + PsTableSearchComponent, + TableRowDetailComponent, + PsTablePaginationComponent, + PsTableColumnDirective, + PsTableColumnTemplateDirective, + PsTableColumnHeaderTemplateDirective, + PsTableTopButtonSectionDirective, + PsTableListActionsDirective, + PsTableRowActionsDirective, + PsTableCustomHeaderDirective, + PsTableRowDetailDirective, + PsTableRowDetailTemplateDirective, + PsTableCustomSettingsDirective, + ], + imports: [ + CommonModule, + FormsModule, + MatSortModule, + MatTableModule, + MatPaginatorModule, + MatCheckboxModule, + MatIconModule, + MatButtonModule, + MatMenuModule, + MatSelectModule, + MatSortModule, + MatInputModule, + MatCardModule, + MatProgressSpinnerModule, + PsFlipContainerModule, + PsSavebarModule, + ], + exports: [ + PsTableComponent, + PsTableColumnDirective, + PsTableColumnTemplateDirective, + PsTableColumnHeaderTemplateDirective, + PsTableTopButtonSectionDirective, + PsTableListActionsDirective, + PsTableRowActionsDirective, + PsTableCustomHeaderDirective, + PsTableRowDetailDirective, + PsTableRowDetailTemplateDirective, + PsTableCustomSettingsDirective, + ], +}) +export class PsTableModule {} From 5dbcea89859557d2cc06d14ee17df17cc87af433 Mon Sep 17 00:00:00 2001 From: Benedikt Langer Date: Wed, 7 Apr 2021 12:03:03 +0200 Subject: [PATCH 2/2] test(table): fixed tests --- .../table-settings.component.spec.ts | 5 +- .../table-sort.component.spec.ts | 15 +++--- .../table/src/table.component.spec.ts | 52 ++++++++++++------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/projects/components/table/src/subcomponents/table-settings.component.spec.ts b/projects/components/table/src/subcomponents/table-settings.component.spec.ts index d69ba768..1333e80e 100644 --- a/projects/components/table/src/subcomponents/table-settings.component.spec.ts +++ b/projects/components/table/src/subcomponents/table-settings.component.spec.ts @@ -17,6 +17,7 @@ import { PsTableSettingsComponent } from './table-settings.component'; import { PsTableSortComponent } from './table-sort.component'; import { By } from '@angular/platform-browser'; import { delay } from 'rxjs/operators'; +import { Sort } from '@angular/material/sort'; @Component({ selector: 'ps-test-component', @@ -202,8 +203,8 @@ describe('PsTableSettingsComponent', () => { sortDirection: sortDirection, } as Partial) as any; } - function createColumnDef(sortColumn: string, sortDirection: 'asc' | 'desc') { - return { sortColumn: sortColumn, sortDirection: sortDirection }; + function createColumnDef(sortColumn: string, sortDirection: 'asc' | 'desc'): Sort { + return { active: sortColumn, direction: sortDirection }; } it('should remove sort column from blacklist', fakeAsync(() => { diff --git a/projects/components/table/src/subcomponents/table-sort.component.spec.ts b/projects/components/table/src/subcomponents/table-sort.component.spec.ts index 80f3065c..30b3219a 100644 --- a/projects/components/table/src/subcomponents/table-sort.component.spec.ts +++ b/projects/components/table/src/subcomponents/table-sort.component.spec.ts @@ -5,6 +5,7 @@ import { MatButton, MatButtonModule } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatSelectModule } from '@angular/material/select'; +import { Sort } from '@angular/material/sort'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IPsTableSortDefinition } from '../models'; @@ -35,7 +36,7 @@ export class TestComponent { @ViewChild(PsTableSortComponent, { static: true }) tableSort: PsTableSortComponent; - public onSortChanged(_event: any) {} + public onSortChanged(_event: Sort) {} } describe('PsTableSortComponent', () => { @@ -62,14 +63,14 @@ describe('PsTableSortComponent', () => { descButton.triggerEventHandler('click', new MouseEvent('click')); expect(component.onSortChanged).toHaveBeenCalledWith({ - sortColumn: 'prop', - sortDirection: 'desc', + active: 'prop', + direction: 'desc', }); ascButton.triggerEventHandler('click', new MouseEvent('click')); expect(component.onSortChanged).toHaveBeenCalledWith({ - sortColumn: 'prop', - sortDirection: 'asc', + active: 'prop', + direction: 'asc', }); component.sortDefinitions = [ @@ -87,8 +88,8 @@ describe('PsTableSortComponent', () => { const itemNode = matOptionNodes.item(1); itemNode.dispatchEvent(new Event('click')); expect(component.onSortChanged).toHaveBeenCalledWith({ - sortColumn: 'newprop', - sortDirection: 'asc', + active: 'newprop', + direction: 'asc', }); }); diff --git a/projects/components/table/src/table.component.spec.ts b/projects/components/table/src/table.component.spec.ts index 6bc23388..fbce7920 100644 --- a/projects/components/table/src/table.component.spec.ts +++ b/projects/components/table/src/table.component.spec.ts @@ -39,7 +39,9 @@ class TestSettingsService extends PsTableSettingsService { } const router: any = { - navigate: (_route: any, _options: any) => {}, + navigate: (_route: any, options: any) => { + queryParams$.next(convertToParamMap(options.queryParams)); + }, }; const queryParams$ = new BehaviorSubject(convertToParamMap({ other: 'value' })); @@ -162,14 +164,25 @@ describe('PsTableComponent', () => { const cd = { markForCheck: () => {} }; let settingsService: TestSettingsService; - function createTableInstance(): PsTableComponent { + function createTableInstance(hooks = false): PsTableComponent { settingsService = new TestSettingsService(); const table = new PsTableComponent(intlService, settingsService, null, cd, route, router, 'de'); table.tableId = 'tableid'; - table.dataSource = new PsTableDataSource(() => of([{ a: 'asdfg' }, { a: 'gasdf' }, { a: 'asdas' }, { a: '32424rw' }])); + table.dataSource = new PsTableDataSource({ + loadDataFn: () => of([{ a: 'asdfg' }, { a: 'gasdf' }, { a: 'asdas' }, { a: '32424rw' }]), + }); + if(hooks){ + table.ngOnChanges({}); + table.ngOnInit(); + table.ngAfterContentInit(); + } return table; } + beforeEach(() => { + queryParams$.next(convertToParamMap({ other: 'value' })); + }); + it('should update table state from the settings service and the query params', fakeAsync(() => { const table = createTableInstance(); settingsService.settings$.next({}); @@ -187,7 +200,7 @@ describe('PsTableComponent', () => { expect(table.pageIndex).toEqual(0); expect(table.filterText).toEqual(''); expect(table.sortColumn).toEqual(null); - expect(table.sortDirection).toEqual('asc'); + expect(table.sortDirection).toEqual(null); expect(table.displayedColumns).toEqual(['select', 'rowDetailExpander', 'prop1', 'prop2', 'options']); expect(settingsService.getStream).toHaveBeenCalledWith(table.tableId, false); @@ -313,7 +326,7 @@ describe('PsTableComponent', () => { })); it('should merge sort definitions and disable sorting on empty', fakeAsync(() => { - const table = createTableInstance(); + const table = createTableInstance(false); const customSortDef = { prop: 'custom', displayName: 'Custom' }; const notSortableColDef = new PsTableColumnDirective(); notSortableColDef.sortable = false; @@ -389,27 +402,30 @@ describe('PsTableComponent', () => { })); it('should update state when sort changes', fakeAsync(() => { - const table = createTableInstance(); - spyOn(table, 'requestUpdate'); - table.onSortChanged({ sortColumn: 'col', sortDirection: 'desc' }); + const table = createTableInstance(true); + spyOn(table, 'requestUpdate').and.callThrough(); + table.onSortChanged({ active: 'col', direction: 'desc' }); + expect((table).requestUpdate).toHaveBeenCalledTimes(1); + tick(1); expect(table.sortColumn).toEqual('col'); expect(table.sortDirection).toEqual('desc'); - expect((table).requestUpdate).toHaveBeenCalledTimes(1); })); it('should update state when filter changes', fakeAsync(() => { - const table = createTableInstance(); - spyOn(table, 'requestUpdate'); + const table = createTableInstance(true); + spyOn(table, 'requestUpdate').and.callThrough(); table.onSearchChanged('test'); - expect(table.filterText).toEqual('test'); expect((table).requestUpdate).toHaveBeenCalledTimes(1); + tick(1); + expect(table.filterText).toEqual('test'); })); it('should update state when page changes and emit output', fakeAsync(() => { - const table = createTableInstance(); + const table = createTableInstance(true); spyOn(table.page, 'emit'); - spyOn(table, 'requestUpdate'); + spyOn(table, 'requestUpdate').and.callThrough(); table.onPage({ pageIndex: 5, pageSize: 3, length: 20, previousPageIndex: 4 }); + tick(1); expect(table.pageIndex).toEqual(5); expect(table.pageSize).toEqual(3); expect((table).requestUpdate).toHaveBeenCalledTimes(1); @@ -664,16 +680,16 @@ describe('PsTableComponent', () => { spyOn(component.table, 'onSortChanged'); await sortSelect.clickOptions({ text: 'id' }); expect(component.table.onSortChanged).toHaveBeenCalledWith({ - sortColumn: 'id', - sortDirection: 'asc', + active: 'id', + direction: null, }); const sortDirectionButtons = await table.getSortDirectionButtons(); expect(sortDirectionButtons.length).toEqual(2); await sortDirectionButtons[0].click(); expect(component.table.onSortChanged).toHaveBeenCalledWith({ - sortColumn: 'id', - sortDirection: 'desc', + active: 'id', + direction: 'desc', }); });