WIP: MEGAFILTER

master
Max 4 years ago
parent bb9dc0f1ed
commit edd29ccec8

@ -30,28 +30,8 @@
>
<mat-icon class="spin">add</mat-icon>
</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
*ngIf="!filter.onlyUnsaved && countUnsavedRows() > 0"
*ngIf="!filters['onlyUnsaved'] && countUnsavedRows() > 0"
mat-raised-button
color="accent"
class="table-control-button"
@ -62,9 +42,9 @@
{{ countUnsavedRows() }} ungespeicherte(s) Element(e) anzeigen
</button>
<mat-checkbox
*ngIf="filter.onlyUnsaved"
*ngIf="filters['onlyUnsaved']"
(change)="showOnlyUnsavedElements(false)"
[(ngModel)]="filter.onlyUnsaved"
[(ngModel)]="filters['onlyUnsaved']"
>
nur ungespeicherte Elemente anzeigen
</mat-checkbox>
@ -86,6 +66,88 @@
<!--- Note that these columns can be defined in any order.
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 -->
<ng-container matColumnDef="select" sticky>
<th mat-header-cell *matHeaderCellDef>
@ -331,6 +393,10 @@
</ng-container>
<!-- Table Definition -->
<tr
mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>

@ -56,12 +56,11 @@
}
.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 {
box-shadow:inset 0 0 0 99999px rgba(0, 0, 0, 0.1);
.mat-table-sticky {
box-shadow: inset 0 0 0 99999px rgba(0, 0, 0, 0.1);
}
.button-wrapper {

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

Loading…
Cancel
Save