Add Megafilter to reference tables

master
Max Ehrlicher-Schmidt 4 years ago
parent 78d77ad1a8
commit 33c859b4f1

@ -1,5 +1,15 @@
<div class="table-page-wrapper"> <div class="table-page-wrapper">
<div class="table-control"> <div class="table-control">
<button
mat-raised-button
color="primary"
class="table-control-button"
*ngIf="columnFiltersAreSet()"
i18n
(click)="resetColumnFilters()"
>
Filter zurücksetzen
</button>
<div *ngIf="editableReferences"> <div *ngIf="editableReferences">
<app-autocomplete-select <app-autocomplete-select
[editable]="editable" [editable]="editable"
@ -10,26 +20,6 @@
(selectedElementChange)="addReference($event)" (selectedElementChange)="addReference($event)"
></app-autocomplete-select> ></app-autocomplete-select>
</div> </div>
<mat-form-field class="filter">
<mat-label>Tabelle filtern</mat-label>
<input
matInput
[(ngModel)]="tableFilterString"
(ngModelChange)="newFilterStringValue()"
placeholder="Suchbegriff eingeben..."
/>
<button
mat-button
*ngIf="tableFilterString"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="tableFilterString = ''; applyTableFilter()"
color="accent"
>
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<mat-paginator <mat-paginator
[pageSizeOptions]="[15, 25]" [pageSizeOptions]="[15, 25]"
showFirstLastButtons showFirstLastButtons
@ -40,6 +30,36 @@
<!--- Note that these columns can be defined in any order. <!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" --> The actual rendered columns are set as a property on the row definition" -->
<!-- Filter Header Row -->
<ng-container
*ngFor="let column of columnInfo"
[matColumnDef]="column.dataPath + '.filter'"
[sticky]="isStickyColumn(column.dataPath)"
><th mat-header-cell *matHeaderCellDef>
<app-filter-row
*ngIf="filters.columnFilters[column.dataPath]?.isSet"
[column]="column"
[(filter)]="filters.columnFilters[column.dataPath]"
(filtersChange)="newFilterValue()"
></app-filter-row>
<button
mat-icon-button
matTooltip="Filter hinzufügen"
*ngIf="!filters.columnFilters[column.dataPath]?.isSet"
(click)="
filters.columnFilters[column.dataPath].isSet = true;
setTableFilterRowHeight()
"
>
<mat-icon>filter_list</mat-icon>
</button>
</th>
</ng-container>
<!-- empty filter cell -->
<ng-container matColumnDef="buttons.filter">
<th mat-header-cell *matHeaderCellDef></th>
</ng-container>
<!-- Other Columns --> <!-- Other Columns -->
<ng-container <ng-container
*ngFor="let column of columnInfo" *ngFor="let column of columnInfo"
@ -96,7 +116,16 @@
</ng-container> </ng-container>
<!-- Table Definition --> <!-- Table Definition -->
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr
mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
#filterRow
></tr>
<tr
mat-header-row
#headerRow
*matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</div> </div>

@ -1,5 +1,6 @@
import { import {
Component, Component,
ElementRef,
EventEmitter, EventEmitter,
Input, Input,
Output, Output,
@ -11,7 +12,7 @@ import { SchemaService } from 'src/app/services/schema.service';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator'; import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort'; import { MatSort } from '@angular/material/sort';
import { FormControl, FormGroup } from '@angular/forms'; import { customTableFilterFunction } from 'src/app/helperFunctions/customTableFilterFunction';
import { Subject } from 'rxjs/internal/Subject'; import { Subject } from 'rxjs/internal/Subject';
import { debounceTime } from 'rxjs/internal/operators/debounceTime'; import { debounceTime } from 'rxjs/internal/operators/debounceTime';
@ -28,6 +29,7 @@ export class ReferenceTableComponent {
translation: string; translation: string;
sticky?: boolean; sticky?: boolean;
type?: string; type?: string;
list?: boolean; //whether the type is a list
link?: (row: any) => string; link?: (row: any) => string;
}[] = []; }[] = [];
@ -77,6 +79,9 @@ export class ReferenceTableComponent {
@ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
@ViewChild('filterRow', { read: ElementRef }) filterRow: ElementRef;
@ViewChild('headerRow', { read: ElementRef }) headerRow: ElementRef;
displayedColumns: string[] = []; displayedColumns: string[] = [];
/** data source of the table */ /** data source of the table */
@ -86,8 +91,9 @@ export class ReferenceTableComponent {
reloadingTable = false; reloadingTable = false;
tableFilterString = ''; displayedFilterColumns = [];
filterStringChanged: Subject<string> = new Subject<string>(); filters: any = {};
filterChanged: Subject<any> = new Subject<any>();
constructor(private schemaService: SchemaService) {} constructor(private schemaService: SchemaService) {}
@ -99,16 +105,26 @@ export class ReferenceTableComponent {
if (this.editableReferences) { if (this.editableReferences) {
this.displayedColumns.push('buttons'); this.displayedColumns.push('buttons');
} }
this.displayedFilterColumns = this.displayedColumns.map(
(columnName) => columnName + '.filter'
);
this.filterStringChanged this.dataSource.filterPredicate = customTableFilterFunction;
.pipe(debounceTime(400)) this.resetFilters();
.subscribe(() => this.applyTableFilter());
} }
ngAfterViewInit() { ngAfterViewInit() {
this.setTableFilterRowHeight();
this.dataSource.paginator = this.paginator; this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
this.dataSource.filter = (this.filters as unknown) as string;
this.filterChanged.pipe(debounceTime(400)).subscribe(() => {
this.applyFilters();
});
this.dataSource.sortingDataAccessor = (item, columnName) => { this.dataSource.sortingDataAccessor = (item, columnName) => {
if (typeof item[columnName] === 'string') { if (typeof item[columnName] === 'string') {
return item[columnName].toLocaleLowerCase(); return item[columnName].toLocaleLowerCase();
@ -166,8 +182,7 @@ export class ReferenceTableComponent {
addReference(row: any) { addReference(row: any) {
this.dataSource.data = [flatten(row), ...this.dataSource.data]; this.dataSource.data = [flatten(row), ...this.dataSource.data];
this.idsOfObjectsToHide = [row.id, ...this.idsOfObjectsToHide]; this.idsOfObjectsToHide = [row.id, ...this.idsOfObjectsToHide];
this.tableFilterString = ''; this.resetFilters();
this.applyTableFilter();
this.onReferenceChange(); this.onReferenceChange();
} }
@ -175,14 +190,6 @@ export class ReferenceTableComponent {
return this.dataSource.data.find((row) => row.id === id); return this.dataSource.data.find((row) => row.id === id);
} }
newFilterStringValue(): void {
this.filterStringChanged.next(this.tableFilterString);
}
applyTableFilter() {
this.dataSource.filter = this.tableFilterString;
}
onReferenceChange() { onReferenceChange() {
const ids = []; const ids = [];
for (const element of this.data) { for (const element of this.data) {
@ -190,4 +197,58 @@ export class ReferenceTableComponent {
} }
this.referenceIds.emit(ids); this.referenceIds.emit(ids);
} }
/** Filter functions **************************************************************/
newFilterValue(): void {
this.filterChanged.next(this.filters);
}
applyFilters(): void {
this.dataSource.filter = (this.filters as unknown) as string;
}
columnFiltersAreSet(): boolean {
for (const filterObject of Object.keys(this.filters.columnFilters)) {
if (this.filters.columnFilters[filterObject].isSet) {
return true;
}
}
return false;
}
resetColumnFilters() {
this.filters['columnFilters'] = [];
for (const column of this.columnInfo) {
this.filters.columnFilters[column.dataPath] = {
isSet: false,
value: null,
minValue: {},
maxValue: {},
fromValue: {},
toValue: {},
type: column.type,
list: column.list,
options: {},
};
}
this.setTableFilterRowHeight();
this.applyFilters();
}
resetFilters() {
this.filters = [];
this.resetColumnFilters();
}
setTableFilterRowHeight() {
setTimeout(() => {
const filterRowHeight = this.filterRow.nativeElement.clientHeight;
const headerRowCells = Array.from(
this.headerRow.nativeElement.children as HTMLCollectionOf<HTMLElement>
);
for (let i = 0; i < headerRowCells.length; i++) {
headerRowCells[i].style.top = filterRowHeight + 'px';
}
});
}
} }

@ -354,12 +354,12 @@
<tr <tr
mat-header-row mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true" *matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row" #filterRow
></tr> ></tr>
<tr <tr
mat-header-row mat-header-row
*matHeaderRowDef="displayedColumns; sticky: true" *matHeaderRowDef="displayedColumns; sticky: true"
class="header-row" #headerRow
></tr> ></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>

@ -7,6 +7,7 @@ import {
ViewChild, ViewChild,
AfterViewInit, AfterViewInit,
ChangeDetectorRef, ChangeDetectorRef,
ElementRef,
} from '@angular/core'; } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { flatten } from 'src/app/helperFunctions/flattenObject'; import { flatten } from 'src/app/helperFunctions/flattenObject';
@ -22,7 +23,6 @@ import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/internal/operators/debounceTime'; import { debounceTime } from 'rxjs/internal/operators/debounceTime';
import { SelectObjectDialogComponent } from '../select-object-dialog/select-object-dialog.component'; import { SelectObjectDialogComponent } from '../select-object-dialog/select-object-dialog.component';
import { filter } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-table', selector: 'app-table',
@ -66,6 +66,9 @@ export class TableComponent implements AfterViewInit {
@ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
@ViewChild('filterRow', { read: ElementRef }) filterRow: ElementRef;
@ViewChild('headerRow', { read: ElementRef }) headerRow: ElementRef;
additionalColumnsFront: string[] = []; additionalColumnsFront: string[] = [];
additionalColumnsBack: string[] = ['buttons']; additionalColumnsBack: string[] = ['buttons'];
displayedColumns: string[] = []; displayedColumns: string[] = [];
@ -456,6 +459,7 @@ export class TableComponent implements AfterViewInit {
}; };
} }
this.setTableFilterRowHeight(); this.setTableFilterRowHeight();
this.applyFilters();
} }
resetFilters() { resetFilters() {
@ -465,11 +469,9 @@ export class TableComponent implements AfterViewInit {
setTableFilterRowHeight() { setTableFilterRowHeight() {
setTimeout(() => { setTimeout(() => {
const filterRowHeight = document.getElementsByClassName('filter-row')[0] const filterRowHeight = this.filterRow.nativeElement.clientHeight;
.clientHeight;
const headerRowCells = Array.from( const headerRowCells = Array.from(
document.getElementsByClassName('header-row')[0] this.headerRow.nativeElement.children as HTMLCollectionOf<HTMLElement>
.children as HTMLCollectionOf<HTMLElement>
); );
for (let i = 0; i < headerRowCells.length; i++) { for (let i = 0; i < headerRowCells.length; i++) {
headerRowCells[i].style.top = filterRowHeight + 'px'; headerRowCells[i].style.top = filterRowHeight + 'px';

@ -250,7 +250,7 @@ export class BikeComponent implements OnInit {
}, },
{ {
type: 'ReferenceTable', type: 'ReferenceTable',
title: 'Equipment', title: 'Equipments',
dataPath: 'equipment', dataPath: 'equipment',
dataService: null, dataService: null,
columnInfo: [ columnInfo: [

Loading…
Cancel
Save