Skip to content

Commit

Permalink
feat: filter for empty value in data table (#534)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
markuczy authored Oct 11, 2024
1 parent 9c703f8 commit 932e9fb
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 32 deletions.
4 changes: 3 additions & 1 deletion libs/angular-accelerator/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
4 changes: 3 additions & 1 deletion libs/angular-accelerator/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
1 change: 1 addition & 0 deletions libs/angular-accelerator/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -98,15 +99,15 @@ export class DataListGridComponent extends DataSortBase implements OnInit, DoChe
@Input() page = 0
columnTemplates$: Observable<Record<string, TemplateRef<any> | null>> | undefined
_columns$ = new BehaviorSubject<DataTableColumn[]>([])
@Input()
@Input()
get columns(): DataTableColumn[] {
return this._columns$.getValue()
}
set columns(value: DataTableColumn[]) {
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 = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,14 @@
></button>
<p-multiSelect
class="filterMultiSelect"
*ngIf="column.filterable"
[options]="(currentFilterOptions$ | async) || []"
[ngModel]="(currentSelectedFilters$ | async) || []"
*ngIf="column.filterable && (!column.filterType || column.filterType === FilterType.EQUAL)"
[options]="(currentEqualFilterOptions$ | async) || []"
[ngModel]="(currentEqualSelectedFilters$ | async) || []"
[showToggleAll]="true"
emptyFilterMessage="{{ 'OCX_DATA_TABLE.EMPTY_FILTER_MESSAGE' | translate }}"
[displaySelectedLabel]="false"
[resetFilterOnHide]="true"
(onChange)="onFilterChange(column, $event)"
(onChange)="onMultiselectFilterChange(column, $event)"
placeholder="Icon"
appendTo="body"
(onFocus)="onFilterChosen(column)"
Expand All @@ -183,6 +183,32 @@
</ng-container>
</ng-template>
</p-multiSelect>
<p-multiSelect
class="filterMultiSelect"
*ngIf="column.filterable && column.filterType === FilterType.TRUTHY"
[options]="truthyFilterOptions"
[ngModel]="(currentTruthySelectedFilters$ | async) || []"
[showToggleAll]="true"
emptyFilterMessage="{{ 'OCX_DATA_TABLE.EMPTY_FILTER_MESSAGE' | translate }}"
[displaySelectedLabel]="false"
[resetFilterOnHide]="true"
(onChange)="onMultiselectFilterChange(column, $event)"
placeholder="Icon"
appendTo="body"
(onFocus)="onFilterChosen(column)"
[title]="'OCX_DATA_TABLE.FILTER_TITLE' | translate"
[ariaLabel]="'OCX_DATA_TABLE.COLUMN_FILTER_ARIA_LABEL' | translate"
[ariaFilterLabel]="('OCX_DATA_TABLE.FILTER_ARIA_LABEL' | translate: { column: column.nameKey | translate})"
>
<ng-template pTemplate="selectedItems" let-value>
<div
class="pi"
[class.pi-filter]="!((filterAmounts$ | async) || {})[column.id]"
[class.pi-filter-fill]="((filterAmounts$ | async) || {})[column.id] > 0"
></div>
</ng-template>
<ng-template pTemplate="item" let-value> {{value.key | translate}} </ng-template>
</p-multiSelect>
</span>
</div>
</th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
Observable,
combineLatest,
debounceTime,
filter,
first,
map,
mergeMap,
Expand All @@ -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
Expand All @@ -56,7 +58,6 @@ interface TemplatesData {
templateNames: Record<ColumnType, Array<string>>
}

export type Filter = { columnId: string; value: string }
export type Sort = { sortColumn: string; sortDirection: DataSortDirection }

export interface DataTableComponentState {
Expand All @@ -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<Row[]>([])
Expand Down Expand Up @@ -312,8 +314,19 @@ export class DataTableComponent extends DataSortBase implements OnInit, AfterCon
selectedRows$: Observable<unknown[]> | undefined

currentFilterColumn$ = new BehaviorSubject<DataTableColumn | null>(null)
currentFilterOptions$: Observable<SelectItem[]> | undefined
currentSelectedFilters$: Observable<string[]> | undefined
currentEqualFilterOptions$: Observable<SelectItem[]> | undefined
currentEqualSelectedFilters$: Observable<unknown[]> | undefined
truthyFilterOptions = [
{
key: 'OCX_DATA_TABLE.FILTER_YES',
value: true,
},
{
key: 'OCX_DATA_TABLE.FILTER_NO',
value: false,
},
]
currentTruthySelectedFilters$: Observable<unknown[]> | undefined
filterAmounts$: Observable<Record<string, number>> | undefined

overflowActions$: Observable<DataAction[]>
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}

Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 &
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { ColumnType } from './column-type.model'
import { FilterType } from './filter.model'

export interface DataTableColumn {
columnType: ColumnType
nameKey: string
id: string
sortable?: boolean
filterable?: boolean
filterType?: FilterType
predefinedGroupKeys?: string[]
dateFormat?: string
}
6 changes: 6 additions & 0 deletions libs/angular-accelerator/src/lib/model/filter.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Filter = { columnId: string; value: unknown; filterType?: FilterType }

export enum FilterType {
EQUAL = 'EQUAL',
TRUTHY = 'TRUTHY',
}
4 changes: 3 additions & 1 deletion libs/portal-integration-angular/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
4 changes: 3 additions & 1 deletion libs/portal-integration-angular/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down

0 comments on commit 932e9fb

Please sign in to comment.