WIP: MEGAFILTER

master
Max 4 years ago
parent bb9dc0f1ed
commit edd29ccec8

@ -30,28 +30,8 @@
> >
<mat-icon class="spin">add</mat-icon> <mat-icon class="spin">add</mat-icon>
</button> </button>
<mat-form-field class="filter">
<mat-label>Filter</mat-label>
<input
matInput
[(ngModel)]="filter.includesString"
(ngModelChange)="newFilterStringValue()"
placeholder="Suchbegriff eingeben..."
/>
<button
mat-button
*ngIf="filter.includesString"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="filter.includesString = ''; applyFilter()"
color="accent"
>
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<button <button
*ngIf="!filter.onlyUnsaved && countUnsavedRows() > 0" *ngIf="!filters['onlyUnsaved'] && countUnsavedRows() > 0"
mat-raised-button mat-raised-button
color="accent" color="accent"
class="table-control-button" class="table-control-button"
@ -62,9 +42,9 @@
{{ countUnsavedRows() }} ungespeicherte(s) Element(e) anzeigen {{ countUnsavedRows() }} ungespeicherte(s) Element(e) anzeigen
</button> </button>
<mat-checkbox <mat-checkbox
*ngIf="filter.onlyUnsaved" *ngIf="filters['onlyUnsaved']"
(change)="showOnlyUnsavedElements(false)" (change)="showOnlyUnsavedElements(false)"
[(ngModel)]="filter.onlyUnsaved" [(ngModel)]="filters['onlyUnsaved']"
> >
nur ungespeicherte Elemente anzeigen nur ungespeicherte Elemente anzeigen
</mat-checkbox> </mat-checkbox>
@ -86,6 +66,88 @@
<!--- 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>
<mat-form-field
*ngIf="column.type === 'String' || column.type === 'Id'"
>
<input
matInput
[type]="text"
[(ngModel)]="filters.columnFilters[column.dataPath].value"
(ngModelChange)="newFilterValue()"
/>
<button
matTooltip="exakte Übereinstimmung"
mat-button
[color]="
filters.columnFilters[column.dataPath].options['exact']
? 'primary'
: ''
"
matSuffix
mat-icon-button
(click)="
filters.columnFilters[column.dataPath].options[
'exact'
] = !filters.columnFilters[column.dataPath].options['exact'];
newFilterValue()
"
>
<mat-icon>short_text</mat-icon>
</button>
<button
matTooltip="Groß- und Kleinschreibung beachten"
mat-button
[color]="
filters.columnFilters[column.dataPath].options['caseSensitive']
? 'primary'
: ''
"
matSuffix
mat-icon-button
(click)="
filters.columnFilters[column.dataPath].options[
'caseSensitive'
] = !filters.columnFilters[column.dataPath].options[
'caseSensitive'
];
newFilterValue()
"
>
<mat-icon>text_fields</mat-icon>
</button>
<button
*ngIf="filters.columnFilters[column.dataPath].value"
matTooltip="Eingabe löschen"
mat-button
matSuffix
mat-icon-button
(click)="
filters.columnFilters[column.dataPath].value = '';
newFilterValue()
"
>
<mat-icon>cancel</mat-icon>
</button>
</mat-form-field>
<app-number-range-cell
*ngIf="column.type === 'Int' || column.type === 'Float' || column.type === 'Money'"
[editable]="true"
[(min)]="filters.columnFilters[column.dataPath].min"
(minChange)="newFilterValue()"
[(max)]="filters.columnFilters[column.dataPath].max"
(maxChange)="newFilterValue()"
>
</app-number-range-cell>
</th>
</ng-container>
<!-- Checkbox Column --> <!-- Checkbox Column -->
<ng-container matColumnDef="select" sticky> <ng-container matColumnDef="select" sticky>
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
@ -331,6 +393,10 @@
</ng-container> </ng-container>
<!-- Table Definition --> <!-- Table Definition -->
<tr
mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr mat-header-row *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>

@ -56,12 +56,11 @@
} }
.highlighted-column { .highlighted-column {
box-shadow:inset 0 0 0 99999px rgba(0, 0, 0, 0.05); box-shadow: inset 0 0 0 99999px rgba(0, 0, 0, 0.05);
} }
.mat-table-sticky { .mat-table-sticky {
box-shadow:inset 0 0 0 99999px rgba(0, 0, 0, 0.1); box-shadow: inset 0 0 0 99999px rgba(0, 0, 0, 0.1);
} }
.button-wrapper { .button-wrapper {

@ -68,6 +68,9 @@ export class TableComponent implements AfterViewInit {
additionalColumnsBack: string[] = ['buttons']; additionalColumnsBack: string[] = ['buttons'];
displayedColumns: string[] = []; displayedColumns: string[] = [];
displayedFilterColumns = [];
filters: any = {};
loadingRowIds: string[] = []; loadingRowIds: string[] = [];
/** data source of the table */ /** data source of the table */
@ -80,10 +83,9 @@ export class TableComponent implements AfterViewInit {
@Input() @Input()
relockingIntervalDuration = 1000 * 60 * 1; relockingIntervalDuration = 1000 * 60 * 1;
filter = { includesString: '', onlyUnsaved: false };
filterStringChanged: Subject<string> = new Subject<string>();
initialFilter = this.filter; filterChanged: Subject<any> = new Subject<any>();
isLoaded = false; isLoaded = false;
@Output() createEvent = new EventEmitter(); @Output() createEvent = new EventEmitter();
@ -98,12 +100,27 @@ export class TableComponent implements AfterViewInit {
private activatedroute: ActivatedRoute, private activatedroute: ActivatedRoute,
private cdRef: ChangeDetectorRef private cdRef: ChangeDetectorRef
) { ) {
this.filter.includesString = /*this.filter.includesString =
this.activatedroute.snapshot.queryParamMap.get('filter') || ''; this.activatedroute.snapshot.queryParamMap.get('filter') || '';*/
//TODO: add filter from url
} }
ngAfterViewInit(): void { ngOnInit() {
this.addColumnPropertiesFromGQLSchemaToColumnInfo(); this.addColumnPropertiesFromGQLSchemaToColumnInfo();
console.log(this.columnInfo);
this.columnInfo.forEach((column) =>
this.displayedColumns.push(column.dataPath)
);
this.displayedFilterColumns = this.displayedColumns.map(
(columnName) => columnName + '.filter'
);
this.displayedColumns.unshift(...this.additionalColumnsFront);
this.displayedColumns.push(...this.additionalColumnsBack);
this.resetFilters();
}
ngAfterViewInit(): void {
this.data.paginator = this.paginator; this.data.paginator = this.paginator;
this.data.sortingDataAccessor = (item, columnName) => { this.data.sortingDataAccessor = (item, columnName) => {
if (typeof item[columnName] === 'string') { if (typeof item[columnName] === 'string') {
@ -113,10 +130,52 @@ export class TableComponent implements AfterViewInit {
}; };
this.data.sort = this.sort; this.data.sort = this.sort;
this.data.filter = (this.filter as unknown) as string; this.data.filter = (this.filters as unknown) as string;
this.data.filterPredicate = (data, filter: any) => { this.data.filterPredicate = (data, filter: any) => {
const a = !filter.onlyUnsaved || data.newObject || data.isLockedByMe; if (data.newObject) {
const b = return true; // always show new objects
}
if (filter.onlyUnsaved && !data.isLockedByMe) {
return false;
}
for (const filterElementName of Object.keys(filter.columnFilters)) {
const filterElement = filter.columnFilters[filterElementName];
if (filterElement.value) {
if (filterElement.type === 'String' || filterElement.type === 'Id') {
let searchString = filterElement.value.trim();
let dataElement = data[filterElementName]?.trim();
if (!filterElement.options.caseSensitive) {
searchString = searchString.toLowerCase();
dataElement = dataElement.toLowerCase();
}
if (
(filterElement.options.exact && dataElement !== searchString) ||
!dataElement.includes(searchString)
) {
return false;
}
}
}
if (filterElement.min != null || filterElement.max != null) {
if (
filterElement.type === 'Float' ||
filterElement.type === 'Int' ||
filterElement.type === 'Money'
) {
let dataElement = data[filterElementName];
if (dataElement == null) {
return false;
}
if (filterElement.min != null && dataElement < filterElement.min) {
return false;
}
if (filterElement.max != null && dataElement > filterElement.max) {
return false;
}
}
}
}
/*const b =
!filter.includesString || !filter.includesString ||
Object.keys(data).some( Object.keys(data).some(
(k) => (k) =>
@ -125,19 +184,13 @@ export class TableComponent implements AfterViewInit {
.toString() .toString()
.toLowerCase() .toLowerCase()
.includes(filter.includesString.toLowerCase()) .includes(filter.includesString.toLowerCase())
); );*/
return a && b; return true;
}; };
this.filterStringChanged this.filterChanged.pipe(debounceTime(400)).subscribe(() => {
.pipe(debounceTime(400)) this.applyFilters();
.subscribe(() => this.applyFilter()); });
this.columnInfo.forEach((column) =>
this.displayedColumns.push(column.dataPath)
);
this.displayedColumns.unshift(...this.additionalColumnsFront);
this.displayedColumns.push(...this.additionalColumnsBack);
this.dataService.loadingRowIds.subscribe((rowIds) => { this.dataService.loadingRowIds.subscribe((rowIds) => {
this.loadingRowIds = rowIds; this.loadingRowIds = rowIds;
@ -287,7 +340,6 @@ export class TableComponent implements AfterViewInit {
addNewObject() { addNewObject() {
this.paginator.firstPage(); this.paginator.firstPage();
this.setFilter({ ...this.filter, includesString: '' });
this.resetSorting(); this.resetSorting();
this.data.data = [ this.data.data = [
{ newObject: true, id: this.getNewId() }, { newObject: true, id: this.getNewId() },
@ -413,25 +465,36 @@ export class TableComponent implements AfterViewInit {
} }
showOnlyUnsavedElements(value: boolean) { showOnlyUnsavedElements(value: boolean) {
this.filter.onlyUnsaved = value; if (value) {
this.filter.includesString = ''; this.resetFilters();
this.applyFilter(); }
this.filters['onlyUnsaved'] = value;
this.applyFilters();
} }
newFilterStringValue(): void { newFilterValue(): void {
this.filterStringChanged.next(this.filter.includesString); console.log(this.filters);
this.filterChanged.next(this.filters);
} }
applyFilter(): void { applyFilters(): void {
this.data.filter = ({ this.isLoaded = false;
...this.filter, setTimeout(() => {
includesString: this.filter.includesString.trim().toLowerCase(), this.data.filter = (this.filters as unknown) as string;
} as unknown) as string; this.isLoaded = true;
});
} }
setFilter(filterObject) { resetFilters() {
this.filter = filterObject; this.filters = [];
this.applyFilter(); this.filters['columnFilters'] = [];
for (const column of this.columnInfo) {
this.filters.columnFilters[column.dataPath] = {
value: null,
type: column.type,
options: {},
};
}
} }
resetSorting() { resetSorting() {

Loading…
Cancel
Save