From 932e9fba5a9ace1588ee6c655b8a174f2ea20c21 Mon Sep 17 00:00:00 2001 From: markuczy <129275100+markuczy@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:50:41 +0200 Subject: [PATCH] feat: filter for empty value in data table (#534) * feat: yes/no filter options * feat: new approach with filter types * feat: improved filter options with filter type * fix: lint fixes * fix: removed as any cast --- libs/angular-accelerator/assets/i18n/de.json | 4 +- libs/angular-accelerator/assets/i18n/en.json | 4 +- libs/angular-accelerator/src/index.ts | 1 + .../data-list-grid.component.ts | 7 ++- .../data-sort-base/data-sort-base.ts | 25 +++++--- .../data-table/data-table.component.html | 34 +++++++++-- .../data-table/data-table.component.ts | 61 +++++++++++++++---- .../data-view/data-view.component.ts | 3 +- .../interactive-data-view.component.ts | 3 +- .../src/lib/model/data-table-column.model.ts | 2 + .../src/lib/model/filter.model.ts | 6 ++ .../assets/i18n/de.json | 4 +- .../assets/i18n/en.json | 4 +- 13 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 libs/angular-accelerator/src/lib/model/filter.model.ts diff --git a/libs/angular-accelerator/assets/i18n/de.json b/libs/angular-accelerator/assets/i18n/de.json index 0b43e64f..49a2e4bb 100644 --- a/libs/angular-accelerator/assets/i18n/de.json +++ b/libs/angular-accelerator/assets/i18n/de.json @@ -73,7 +73,9 @@ "ARIA_LABEL": "{{column}} {{direction}} sortieren" }, "SELECT_ALL_ARIA_LABEL": "Selektiere alle Zeilen der Tabelle", - "SELECT_ARIA_LABEL": "Selektiere die Tabellenspalte mit der ID {{key}}" + "SELECT_ARIA_LABEL": "Selektiere die Tabellenspalte mit der ID {{key}}", + "FILTER_YES": "Ja", + "FILTER_NO": "Nein" }, "OCX_DATA_LIST_GRID": { "EMPTY_RESULT": "Keine Daten gefunden.", diff --git a/libs/angular-accelerator/assets/i18n/en.json b/libs/angular-accelerator/assets/i18n/en.json index a0b5c98c..f31bd1d4 100644 --- a/libs/angular-accelerator/assets/i18n/en.json +++ b/libs/angular-accelerator/assets/i18n/en.json @@ -73,7 +73,9 @@ "ARIA_LABEL": "Toggle {{column}} sorting direction to {{direction}}" }, "SELECT_ALL_ARIA_LABEL": "Select all table rows", - "SELECT_ARIA_LABEL": "Select table row with id {{key}}" + "SELECT_ARIA_LABEL": "Select table row with id {{key}}", + "FILTER_YES": "Yes", + "FILTER_NO": "No" }, "OCX_DATA_LIST_GRID": { "EMPTY_RESULT": "No data found.", diff --git a/libs/angular-accelerator/src/index.ts b/libs/angular-accelerator/src/index.ts index 87ae2c0a..526e5182 100644 --- a/libs/angular-accelerator/src/index.ts +++ b/libs/angular-accelerator/src/index.ts @@ -38,6 +38,7 @@ export * from './lib/model/data-table-column.model' export * from './lib/model/diagram-column' // export * from './lib/model/diagram-data' export * from './lib/model/diagram-type' +export * from './lib/model/filter.model' // core export * from './lib/angular-accelerator.module' diff --git a/libs/angular-accelerator/src/lib/components/data-list-grid/data-list-grid.component.ts b/libs/angular-accelerator/src/lib/components/data-list-grid/data-list-grid.component.ts index f1e8de0b..22fd801b 100644 --- a/libs/angular-accelerator/src/lib/components/data-list-grid/data-list-grid.component.ts +++ b/libs/angular-accelerator/src/lib/components/data-list-grid/data-list-grid.component.ts @@ -28,7 +28,8 @@ import { DataSortDirection } from '../../model/data-sort-direction' import { DataTableColumn } from '../../model/data-table-column.model' import { ObjectUtils } from '../../utils/objectutils' import { DataSortBase } from '../data-sort-base/data-sort-base' -import { Filter, Row } from '../data-table/data-table.component' +import { Row } from '../data-table/data-table.component' +import { Filter } from '../../model/filter.model' export type ListGridData = { id: string | number @@ -98,7 +99,7 @@ export class DataListGridComponent extends DataSortBase implements OnInit, DoChe @Input() page = 0 columnTemplates$: Observable | null>> | undefined _columns$ = new BehaviorSubject([]) - @Input() + @Input() get columns(): DataTableColumn[] { return this._columns$.getValue() } @@ -106,7 +107,7 @@ export class DataListGridComponent extends DataSortBase implements OnInit, DoChe this._columns$.next(value) const obs = value.map((c) => this.getTemplate(c)) this.columnTemplates$ = combineLatest(obs).pipe( - map(values => Object.fromEntries(value.map((c, i) => [c.id, values[i]]))) + map((values) => Object.fromEntries(value.map((c, i) => [c.id, values[i]]))) ) } @Input() name = '' diff --git a/libs/angular-accelerator/src/lib/components/data-sort-base/data-sort-base.ts b/libs/angular-accelerator/src/lib/components/data-sort-base/data-sort-base.ts index c2884de0..8be9cab6 100644 --- a/libs/angular-accelerator/src/lib/components/data-sort-base/data-sort-base.ts +++ b/libs/angular-accelerator/src/lib/components/data-sort-base/data-sort-base.ts @@ -5,8 +5,9 @@ import { ColumnType } from '../../model/column-type.model' import { DataSortDirection } from '../../model/data-sort-direction' import { DataTableColumn } from '../../model/data-table-column.model' import { ListGridData } from '../../components/data-list-grid/data-list-grid.component' -import { Row, Filter } from '../../components/data-table/data-table.component' +import { Row } from '../../components/data-table/data-table.component' import { ObjectUtils } from '../../utils/objectutils' +import { Filter, FilterType } from '../../model/filter.model' type RowListGridData = ListGridData | Row @@ -72,13 +73,21 @@ export class DataSortBase { .every((filterColumnId) => filters .filter((filter) => filter.columnId === filterColumnId) - .some( - (filter) => - ( - translations[filter.columnId]?.[ObjectUtils.resolveFieldData(item, filter.columnId)?.toString()] || - ObjectUtils.resolveFieldData(item, filter.columnId) - )?.toString() === filter.value.toString() - ) + .some((filter) => { + const value = ( + translations[filter.columnId]?.[ObjectUtils.resolveFieldData(item, filter.columnId)?.toString()] || + ObjectUtils.resolveFieldData(item, filter.columnId) + )?.toString() + switch (filter.filterType) { + case undefined: + case FilterType.EQUAL: + return value === filter.value + case FilterType.TRUTHY: { + const isTruthy = value !== undefined && value !== '' + return filter.value ? isTruthy : !isTruthy + } + } + }) ) ), filters, diff --git a/libs/angular-accelerator/src/lib/components/data-table/data-table.component.html b/libs/angular-accelerator/src/lib/components/data-table/data-table.component.html index 26c97131..df7dc0fc 100644 --- a/libs/angular-accelerator/src/lib/components/data-table/data-table.component.html +++ b/libs/angular-accelerator/src/lib/components/data-table/data-table.component.html @@ -149,14 +149,14 @@ > + + +
+
+ {{value.key | translate}} +
diff --git a/libs/angular-accelerator/src/lib/components/data-table/data-table.component.ts b/libs/angular-accelerator/src/lib/components/data-table/data-table.component.ts index 13168ee2..9f2eeb75 100644 --- a/libs/angular-accelerator/src/lib/components/data-table/data-table.component.ts +++ b/libs/angular-accelerator/src/lib/components/data-table/data-table.component.ts @@ -25,6 +25,7 @@ import { Observable, combineLatest, debounceTime, + filter, first, map, mergeMap, @@ -38,8 +39,9 @@ import { DataTableColumn } from '../../model/data-table-column.model' import { ObjectUtils } from '../../utils/objectutils' import { DataSortBase } from '../data-sort-base/data-sort-base' import { MultiSelectItem } from 'primeng/multiselect' +import { Filter, FilterType } from '../../model/filter.model' -type Primitive = number | string | boolean | bigint | Date +export type Primitive = number | string | boolean | bigint | Date export type Row = { id: string | number [columnId: string]: unknown @@ -56,7 +58,6 @@ interface TemplatesData { templateNames: Record> } -export type Filter = { columnId: string; value: string } export type Sort = { sortColumn: string; sortDirection: DataSortDirection } export interface DataTableComponentState { @@ -73,6 +74,7 @@ export interface DataTableComponentState { styleUrls: ['./data-table.component.scss'], }) export class DataTableComponent extends DataSortBase implements OnInit, AfterContentInit { + FilterType = FilterType TemplateType = TemplateType checked = true _rows$ = new BehaviorSubject([]) @@ -312,8 +314,19 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon selectedRows$: Observable | undefined currentFilterColumn$ = new BehaviorSubject(null) - currentFilterOptions$: Observable | undefined - currentSelectedFilters$: Observable | undefined + currentEqualFilterOptions$: Observable | undefined + currentEqualSelectedFilters$: Observable | undefined + truthyFilterOptions = [ + { + key: 'OCX_DATA_TABLE.FILTER_YES', + value: true, + }, + { + key: 'OCX_DATA_TABLE.FILTER_NO', + value: false, + }, + ] + currentTruthySelectedFilters$: Observable | undefined filterAmounts$: Observable> | undefined overflowActions$: Observable @@ -416,18 +429,43 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon map((params) => this.sortItems(params, this.columns, this.clientSideSorting)), map(([rows]) => this.flattenItems(rows)) ) - this.currentSelectedFilters$ = combineLatest([this._filters$, this.currentFilterColumn$]).pipe( + this.currentTruthySelectedFilters$ = combineLatest([this._filters$, this.currentFilterColumn$]).pipe( + map(([filters, currentFilterColumn]) => { + return filters + .filter( + (filter) => + filter.columnId === currentFilterColumn?.id && currentFilterColumn.filterType === FilterType.TRUTHY + ) + .map((filter) => filter.value) + }) + ) + this.currentEqualSelectedFilters$ = combineLatest([this._filters$, this.currentFilterColumn$]).pipe( map(([filters, currentFilterColumn]) => { - return filters.filter((filter) => filter.columnId === currentFilterColumn?.id).map((filter) => filter.value) + return filters + .filter( + (filter) => + filter.columnId === currentFilterColumn?.id && + (!currentFilterColumn.filterType || currentFilterColumn.filterType === FilterType.EQUAL) + ) + .map((filter) => filter.value) }) ) - this.currentFilterOptions$ = combineLatest([this._rows$, this.currentFilterColumn$, this._filters$]).pipe( + this.currentEqualFilterOptions$ = combineLatest([this._rows$, this.currentFilterColumn$, this._filters$]).pipe( + filter( + ([_, currentFilterColumn, __]) => + !currentFilterColumn?.filterType || currentFilterColumn.filterType === FilterType.EQUAL + ), mergeMap(([rows, currentFilterColumn, filters]) => { if (!currentFilterColumn?.id) { return of([]) } + const currentFilters = filters - .filter((filter) => filter.columnId === currentFilterColumn?.id) + .filter( + (filter) => + filter.columnId === currentFilterColumn?.id && + (!currentFilterColumn.filterType || currentFilterColumn.filterType === FilterType.EQUAL) + ) .map((filter) => filter.value) const columnValues = rows.map((row) => row[currentFilterColumn?.id]) @@ -567,13 +605,14 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon this.currentFilterColumn$.next(column) } - onFilterChange(column: DataTableColumn, event: any) { + onMultiselectFilterChange(column: DataTableColumn, event: any) { const filters = this.filters .filter((filter) => filter.columnId !== column.id) .concat( event.value.map((value: Primitive) => ({ columnId: column.id, value, + filterType: column.filterType, })) ) if (this.clientSideFiltering) { @@ -586,7 +625,7 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon this.resetPage() } - getSelectedFilters(columnId: string): string[] | undefined { + getSelectedFilters(columnId: string): unknown[] | undefined { return this.filters.filter((filter) => filter.columnId === columnId).map((filter) => filter.value) } @@ -629,7 +668,7 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon newSelectionIds = this.mergeWithDisabledKeys(newSelectionIds, disabledRowIds) } } - + this._selectionIds$.next(newSelectionIds) this.selectionChanged.emit(this._rows$.getValue().filter((row) => newSelectionIds.includes(row.id))) this.emitComponentStateChanged() diff --git a/libs/angular-accelerator/src/lib/components/data-view/data-view.component.ts b/libs/angular-accelerator/src/lib/components/data-view/data-view.component.ts index da45415e..daf5db46 100644 --- a/libs/angular-accelerator/src/lib/components/data-view/data-view.component.ts +++ b/libs/angular-accelerator/src/lib/components/data-view/data-view.component.ts @@ -14,13 +14,14 @@ import { ViewChild, } from '@angular/core' import { DataListGridComponent, DataListGridComponentState, ListGridData } from '../data-list-grid/data-list-grid.component' -import { Row, Filter, Sort, DataTableComponent, DataTableComponentState } from '../data-table/data-table.component' +import { Row, Sort, DataTableComponent, DataTableComponentState } from '../data-table/data-table.component' import { DataTableColumn } from '../../model/data-table-column.model' import { DataSortDirection } from '../../model/data-sort-direction' import { DataAction } from '../../model/data-action' import { BehaviorSubject, ReplaySubject, timestamp, combineLatest, map, Observable, startWith } from 'rxjs' import { orderAndMergeValuesByTimestamp } from '../../utils/rxjs-utils' import { PrimeTemplate } from 'primeng/api' +import { Filter } from '../../model/filter.model' export type RowListGridData = ListGridData & Row diff --git a/libs/angular-accelerator/src/lib/components/interactive-data-view/interactive-data-view.component.ts b/libs/angular-accelerator/src/lib/components/interactive-data-view/interactive-data-view.component.ts index 802f4264..f945a5ee 100644 --- a/libs/angular-accelerator/src/lib/components/interactive-data-view/interactive-data-view.component.ts +++ b/libs/angular-accelerator/src/lib/components/interactive-data-view/interactive-data-view.component.ts @@ -39,8 +39,9 @@ import { import { SlotService } from '@onecx/angular-remote-components' import { DataLayoutSelectionComponentState } from '../data-layout-selection/data-layout-selection.component' import { DataListGridSortingComponentState } from '../data-list-grid-sorting/data-list-grid-sorting.component' -import { Filter, Row, Sort } from '../data-table/data-table.component' +import { Row, Sort } from '../data-table/data-table.component' import { DataViewComponent, DataViewComponentState, RowListGridData } from '../data-view/data-view.component' +import { Filter } from '../../model/filter.model' export type InteractiveDataViewComponentState = ColumnGroupSelectionComponentState & CustomGroupColumnSelectorComponentState & diff --git a/libs/angular-accelerator/src/lib/model/data-table-column.model.ts b/libs/angular-accelerator/src/lib/model/data-table-column.model.ts index a2d9f8d6..42982a41 100644 --- a/libs/angular-accelerator/src/lib/model/data-table-column.model.ts +++ b/libs/angular-accelerator/src/lib/model/data-table-column.model.ts @@ -1,4 +1,5 @@ import { ColumnType } from './column-type.model' +import { FilterType } from './filter.model' export interface DataTableColumn { columnType: ColumnType @@ -6,6 +7,7 @@ export interface DataTableColumn { id: string sortable?: boolean filterable?: boolean + filterType?: FilterType predefinedGroupKeys?: string[] dateFormat?: string } diff --git a/libs/angular-accelerator/src/lib/model/filter.model.ts b/libs/angular-accelerator/src/lib/model/filter.model.ts new file mode 100644 index 00000000..c57ce2b4 --- /dev/null +++ b/libs/angular-accelerator/src/lib/model/filter.model.ts @@ -0,0 +1,6 @@ +export type Filter = { columnId: string; value: unknown; filterType?: FilterType } + +export enum FilterType { + EQUAL = 'EQUAL', + TRUTHY = 'TRUTHY', +} diff --git a/libs/portal-integration-angular/assets/i18n/de.json b/libs/portal-integration-angular/assets/i18n/de.json index 0f0f7d30..3b923f78 100644 --- a/libs/portal-integration-angular/assets/i18n/de.json +++ b/libs/portal-integration-angular/assets/i18n/de.json @@ -94,7 +94,9 @@ "ARIA_LABEL": "{{column}} {{direction}} sortieren" }, "SELECT_ALL_ARIA_LABEL": "Selektiere alle Zeilen der Tabelle", - "SELECT_ARIA_LABEL": "Selektiere die Tabellenspalte mit der ID {{key}}" + "SELECT_ARIA_LABEL": "Selektiere die Tabellenspalte mit der ID {{key}}", + "FILTER_YES": "Ja", + "FILTER_NO": "Nein" }, "OCX_DATA_LIST_GRID": { "EMPTY_RESULT": "Keine Daten gefunden.", diff --git a/libs/portal-integration-angular/assets/i18n/en.json b/libs/portal-integration-angular/assets/i18n/en.json index 849c63d3..bf8467d7 100644 --- a/libs/portal-integration-angular/assets/i18n/en.json +++ b/libs/portal-integration-angular/assets/i18n/en.json @@ -94,7 +94,9 @@ "ARIA_LABEL": "Toggle {{column}} sorting direction to {{direction}}" }, "SELECT_ALL_ARIA_LABEL": "Select all table rows", - "SELECT_ARIA_LABEL": "Select table row with id {{key}}" + "SELECT_ARIA_LABEL": "Select table row with id {{key}}", + "FILTER_YES": "Yes", + "FILTER_NO": "No" }, "OCX_DATA_LIST_GRID": { "EMPTY_RESULT": "No data found.",