Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): allow developer to pass array for table filter options to allow from select options #13040

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
key="name"
label="Name"
align="start"
[filterSelectOptions]="selectOptions"
[sortable]="true"
[filterable]="true"
[dataType]="dataTypeEnum.STRING"
>
</fdp-column>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { DatetimeAdapter, FdDate, FdDatetimeModule } from '@fundamental-ngx/core/datetime';
import { FdDate, FdDatetimeModule } from '@fundamental-ngx/core/datetime';
import { PlatformTableModule } from '@fundamental-ngx/platform/table';
import {
ChildTableDataSource,
CollectionBooleanFilter,
CollectionDateFilter,
CollectionNumberFilter,
CollectionStringFilter,
FdpTableDataSource,
Expand Down Expand Up @@ -46,6 +44,7 @@ export class AdvancedScrollingExampleComponent {
childSource: ChildTableDataSource<ExampleItem>;
readonly filterTypeEnum = FilterType;
readonly dataTypeEnum = FilterableColumnDataType;
readonly selectOptions = ['Laptops 1 (Level 1)', 'Laptops 12 (Level 1)'];

constructor() {
this.source = new TableDataSource(new TableDataProviderExample());
Expand Down Expand Up @@ -125,6 +124,23 @@ class ChildTableProviderExample extends TableChildrenDataProvider<ExampleItem> {
return of(itemsMap).pipe(delay(1000));
}

search(items: ExampleItem[], { searchInput, columnKeys }: TableState): ExampleItem[] {
const searchText = searchInput?.text || '';
const keysToSearchBy = columnKeys;

if (searchText.trim() === '' || keysToSearchBy.length === 0) {
return items;
}

return items.filter((item) => {
const valuesForSearch = keysToSearchBy.map((key) => getNestedValue(key, item));
return valuesForSearch
.filter((value) => !!value)
.map((value): string => value.toString())
.some((value) => value.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()));
});
}

private filter(items: ExampleItem[], { filterBy }: TableState): ExampleItem[] {
filterBy
.filter(({ field }) => !!field)
Expand All @@ -147,23 +163,6 @@ class ChildTableProviderExample extends TableChildrenDataProvider<ExampleItem> {
return items;
}

search(items: ExampleItem[], { searchInput, columnKeys }: TableState): ExampleItem[] {
const searchText = searchInput?.text || '';
const keysToSearchBy = columnKeys;

if (searchText.trim() === '' || keysToSearchBy.length === 0) {
return items;
}

return items.filter((item) => {
const valuesForSearch = keysToSearchBy.map((key) => getNestedValue(key, item));
return valuesForSearch
.filter((value) => !!value)
.map((value): string => value.toString())
.some((value) => value.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()));
});
}

private sort(items: ExampleItem[], { sortBy }: TableState): ExampleItem[] {
sortBy = sortBy.filter(({ field }) => !!field);

Expand Down Expand Up @@ -224,6 +223,23 @@ export class TableDataProviderExample extends TableDataProvider<ExampleItem> {
return of(this.items).pipe(delay(1000));
}

search(items: ExampleItem[], { searchInput, columnKeys }: TableState): ExampleItem[] {
const searchText = searchInput?.text || '';
const keysToSearchBy = columnKeys;

if (searchText.trim() === '' || keysToSearchBy.length === 0) {
return items;
}

return items.filter((item) => {
const valuesForSearch = keysToSearchBy.map((key) => getNestedValue(key, item));
return valuesForSearch
.filter((value) => !!value)
.map((value): string => value.toString())
.some((value) => value.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()));
});
}

private filter(items: ExampleItem[], { filterBy }: TableState): ExampleItem[] {
filterBy
.filter(({ field }) => !!field)
Expand All @@ -246,23 +262,6 @@ export class TableDataProviderExample extends TableDataProvider<ExampleItem> {
return items;
}

search(items: ExampleItem[], { searchInput, columnKeys }: TableState): ExampleItem[] {
const searchText = searchInput?.text || '';
const keysToSearchBy = columnKeys;

if (searchText.trim() === '' || keysToSearchBy.length === 0) {
return items;
}

return items.filter((item) => {
const valuesForSearch = keysToSearchBy.map((key) => getNestedValue(key, item));
return valuesForSearch
.filter((value) => !!value)
.map((value): string => value.toString())
.some((value) => value.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()));
});
}

private sort({ sortBy }: TableState): ExampleItem[] {
const items = this.items.slice();

Expand Down Expand Up @@ -382,53 +381,3 @@ const filterByNumber = (item: ExampleItem, filter: CollectionNumberFilter): bool

return filter.exclude ? !result : result;
};

const filterByDate = <D = FdDate>(
item: ExampleItem,
filter: CollectionDateFilter,
adapter: DatetimeAdapter<D>
): boolean => {
const filterValue = filter.value;
const filterValue2 = filter.value2;
const itemValue = getNestedValue(filter.field, item);
const diff = adapter.compareDate(itemValue, filterValue);
let result = false;

switch (filter.strategy) {
case 'after':
result = diff > 0;
break;
case 'onOrAfter':
result = diff >= 0;
break;
case 'before':
result = diff < 0;
break;
case 'beforeOrOn':
result = diff <= 0;
break;
case 'between':
result = adapter.isBetween(itemValue, filterValue, filterValue2);
break;

case 'equalTo':
default:
result = adapter.dateTimesEqual(itemValue, filterValue);
}

return filter.exclude ? !result : result;
};

const filterByBoolean = (item: ExampleItem, filter: CollectionBooleanFilter): boolean => {
const filterValue = filter.value;
const itemValue = getNestedValue(filter.field, item);
let result = false;

switch (filter.strategy) {
case 'equalTo':
default:
result = itemValue === filterValue;
}

return filter.exclude ? !result : result;
};
6 changes: 6 additions & 0 deletions libs/platform/table-helpers/table-column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export abstract class TableColumn {
/** Data type the column represents. */
abstract dataType: FilterableColumnDataType;

/**
* Optional array of available filter options.
* Providing values to this input will cause the filter to change from a text-type input to a select-type input.
* */
abstract filterSelectOptions: string[];

/** Width of the column cells. */
abstract width: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ export class TableColumnComponent extends TableColumn implements OnInit, OnChang
@Input()
dataType: FilterableColumnDataType = FilterableColumnDataType.STRING;

/**
* Optional array of available filter options.
* Providing values to this input will cause the filter to change from a text-type input to a select-type input.
* */
@Input()
filterSelectOptions: string[] = [];

/** Toggles grouping feature for the column. */
@Input()
groupable = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@
{{ 'platformTable.P13FilterBooleanOptionFalse' | fdTranslate }}
</li>
</fd-select>
} @else if (rule.filterSelectOptions?.length) {
<!-- Filter options dropdown menu -->
<fd-select
[ngModel]="rule[valueKey]"
(ngModelChange)="rule.setValue($event); _onModelChange()"
[required]="true"
[name]="valueKey"
class="filter-row__select"
>
@for (option of rule.filterSelectOptions; track $index) {
<li fd-option [value]="option">{{ option }}</li>
}
</fd-select>
} @else {
<input
type="text"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface FilterableColumn {
key: string;
dataType: FilterableColumnDataType;
filterable?: boolean;
filterSelectOptions?: string[]; // add optional filterSelectOptions
}

export interface FilterDialogData extends TableDialogCommonData {
Expand Down Expand Up @@ -39,6 +40,12 @@ export class FilterRule<T = any> {
/** Data type */
dataType?: FilterableColumnDataType;

/**
* Optional array of available filter options.
* Providing values to this input will cause the filter to change from a text-type input to a select-type input.
* */
filterSelectOptions: string[] = [];

/** returns whether filter rule has value */
get hasValue(): boolean {
return this.valueExists(this.value) || this.valueExists(this.value2);
Expand All @@ -65,6 +72,9 @@ export class FilterRule<T = any> {
if (this.strategies.length === 0) {
this.setStrategiesByColumnKey(this.columnKey);
}
if (this.filterSelectOptions.length === 0) {
this.setFilterSelectOptionsByColumnKey(this.columnKey);
}
}

/** @hidden */
Expand Down Expand Up @@ -121,21 +131,25 @@ export class FilterRule<T = any> {
// update data type
this.setDataTypeByColumnKey(columnKey);

// update available Filter options
this.setFilterSelectOptionsByColumnKey(columnKey);

// update available strategies list
this.setStrategiesByColumnKey(columnKey);
}

/** @hidden */
setDataTypeByColumnKey(columnKey?: string): void {
const dataType = this.columns.find((column) => column.key === columnKey)?.dataType;

if (dataType === this.dataType) {
return;
}

this.dataType = dataType;
}

/** @hidden */
setFilterSelectOptionsByColumnKey(columnKey?: string): void {
const filterSelectOptions = this.columns.find((column) => column.key === columnKey)?.filterSelectOptions;
this.filterSelectOptions = filterSelectOptions ? filterSelectOptions : [];
}

/** @hidden */
private valueExists(value: any): boolean {
return !!value || value === 0 || typeof value === 'boolean';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,14 @@ export class TableP13DialogComponent implements OnDestroy {
const columns = this._getTableColumns();
const filterBy = state?.filterBy;
const dialogData: FilterDialogData = {
columns: columns.map(({ label, key, dataType, filterable }) => ({ label, key, dataType, filterable })),
// add filterSelectOptions to be sent with the data
columns: columns.map(({ label, key, dataType, filterable, filterSelectOptions }) => ({
label,
key,
dataType,
filterable,
filterSelectOptions
})),
collectionFilter: filterBy
};

Expand Down