Skip to content

Commit

Permalink
feat(platform): vhd custom filter controls and column renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
N1XUS committed Dec 13, 2023
1 parent 8f5499f commit 45d067b
Show file tree
Hide file tree
Showing 19 changed files with 436 additions and 35 deletions.
2 changes: 1 addition & 1 deletion libs/core/src/lib/combobox/combobox.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ export class ComboboxComponent

/** @hidden */
private _defaultDisplay(str: any): string {
return str;
return `${str}`;
}

/** @hidden */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<button
fd-button
aria-label="Open value help dialog"
title="Open value help dialog"
glyph="value-help"
(click)="vhd.open()"
label="Open value help dialog"
></button>
<br />
<div *ngIf="actualItems.length">
<fd-tokenizer fdCompact>
<fd-token *ngFor="let token of actualItems" [readOnly]="true">{{ token }}</fd-token>
</fd-tokenizer>
</div>
<fdp-value-help-dialog
#vhd
fdCompact
dialogTitle="Simple value help dialog"
uniqueKey="id"
tokenViewField="name"
[formatToken]="formatTokenFn"
[dataSource]="dataSource"
(valueChange)="valueChange($event)"
headerId="fdp-vhd-header-1"
>
<ng-container *fdpValueHelpColumnDef="let row; column: 'verified'; let colName = key; let value = value">
{{ value ? 'Yes' : 'No' }}
</ng-container>
<ng-container *ngFor="let filter of filters; let i = index">
<fdp-value-help-dialog-filter
*ngIf="filter.key === 'verified'"
[main]="true"
[key]="filter.key"
[label]="filter.label"
[advanced]="true"
>
<fd-select
*fdpValueHelpFilterDef="let filterModel"
[(ngModel)]="filterModel.value"
fd-form-control
class="vhd-custom-select"
>
<li *ngFor="let option of booleanDropdownValues" fd-option [value]="option.value">
<span fd-list-title>{{ option.displayValue }}</span>
</li>
</fd-select>
</fdp-value-help-dialog-filter>
<fdp-value-help-dialog-filter
*ngIf="filter.key !== 'verified'"
[main]="i < 2"
[key]="filter.key"
[label]="filter.label"
[advanced]="i !== 0"
></fdp-value-help-dialog-filter>
</ng-container>
</fdp-value-help-dialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { Component, ViewEncapsulation } from '@angular/core';
import {
ValueHelpDialogDataSource,
VhdDataProvider,
VhdDefineExcludeStrategy,
VhdDefineIncludeStrategy,
VhdExcludedEntity,
VhdIncludedEntity,
VhdValue,
VhdValueChangeEvent
} from '@fundamental-ngx/platform/value-help-dialog';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';

interface ExampleTestModel {
id: number;
name: string;
code: string;
city: string;
zipcode: string;
address: string;
nickname: string;
verified: boolean;
}

interface FilterData {
key: string;
name: string;
label: string;
advanced: boolean;
}

const exampleDataSource = (): { dataSource: ExampleTestModel[]; filters: FilterData[] } => {
const dataSource = Array(137)
.fill(null)
.map((_value, index) => ({
id: index + 1,
name: `Name ${index + 1}`,
code: `${Math.floor(Math.random() * 99999)}`,
city: `City ${Math.floor(Math.random() * index)}`,
zipcode: `zipcode ${Math.floor(Math.random() * index)}`,
address: `Address ${Math.floor(Math.random() * index)}`,
nickname: `Nickname ${Math.floor(Math.random() * index)}`,
verified: Math.random() < 0.5
}));
return {
dataSource,
filters: Object.keys(dataSource[0]).map((value, index) => ({
key: value,
name: `${value}`,
label: `Product ${value}`,
advanced: index > 0
}))
};
};

const data = exampleDataSource();

@Component({
selector: 'fdp-vhd-column-template-example',
styles: [
`
.vhd-custom-select {
display: block !important;
}
`
],
templateUrl: './platform-vhd-column-template-example.component.html',
encapsulation: ViewEncapsulation.None
})
export class PlatformVhdColumnTemplateExampleComponent {
filters = data.filters;
dataSource = new ValueHelpDialogDataSource(new DelayedVhdDataProvider(data.dataSource));

actualValue: Partial<VhdValue<ExampleTestModel>> = {};

booleanDropdownValues = [
{ value: true, displayValue: 'Yes' },
{ value: false, displayValue: 'No' }
];

actualItems: string[] = [];
formatTokenFn = (value: VhdValueChangeEvent<ExampleTestModel>): void => {
this.actualItems = [
...(value.selected || []).map((item) => item.name),
...(value.conditions || []).map((item) => this.conditionDisplayFn(item))
].filter((v): v is string => !!v);
};
conditionDisplayFn = (item: VhdIncludedEntity | VhdExcludedEntity): string | null => {
let value = (() => {
switch (item.strategy) {
case VhdDefineIncludeStrategy.empty:
case VhdDefineExcludeStrategy.not_empty:
return null;
case VhdDefineIncludeStrategy.between:
return `${item.value}...${item.valueTo}`;
case VhdDefineIncludeStrategy.contains:
return `*${item.value}*`;
case VhdDefineIncludeStrategy.equalTo:
return `=${item.value}`;
case VhdDefineIncludeStrategy.startsWith:
return `${item.value}*`;
case VhdDefineIncludeStrategy.endsWith:
return `*${item.value}`;
case VhdDefineIncludeStrategy.greaterThan:
return `>${item.value}`;
case VhdDefineIncludeStrategy.greaterThanEqual:
return `>=${item.value}`;
case VhdDefineIncludeStrategy.lessThan:
return `<${item.value}`;
case VhdDefineIncludeStrategy.lessThanEqual:
return `<=${item.value}`;
case VhdDefineExcludeStrategy.not_equalTo:
return `!(=${item.value})`;
}
})();
if (value && item.type === 'exclude') {
value = `!(${value})`;
}

return value;
};

valueChange($event: VhdValueChangeEvent<ExampleTestModel>): void {
this.actualValue = { ...$event };
}
}

// Simulating real http request by adding 300ms delay to the DataProvider's "fetch" method
class DelayedVhdDataProvider<R extends object> extends VhdDataProvider<R> {
// Override default fetch method to be able to deal with booleans.
// Developers should implement own logic of filtering the data. E.g. sending http request to the backend.
fetch(params: Map<string, string>): Observable<R[]> {
let data = this.values;
const arrayParams = Array.from(params);
const filterFn = (row: R): boolean => {
const rowEntries = Object.entries(row) as string[][];
return arrayParams.every(([key, value]) => {
if (key === '*') {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return rowEntries.some(([_rowEntryKey, rowEntryValue]) => this._search(rowEntryValue, value));
} else {
return this._search(row[key], value);
}
});
};
if (params.size) {
data = this.values.filter(filterFn);
}
return of(data).pipe(delay(300));
}

private _search(rowEntryValue: any, value: any): boolean {
if (typeof value === 'boolean') {
return rowEntryValue === value;
} else {
return String(rowEntryValue).toLowerCase().includes(value.toLowerCase());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,28 @@
(valueChange)="valueChange($event)"
headerId="fdp-vhd-header-1"
>
<fdp-value-help-dialog-filter
*ngFor="let filter of filters; index as i"
[main]="i < 2"
[key]="filter.key"
[label]="filter.label"
[advanced]="i !== 0"
></fdp-value-help-dialog-filter>
<ng-container *ngFor="let filter of filters; let i = index">
<fdp-value-help-dialog-filter
*ngIf="filter.key === 'verified'"
[main]="true"
[key]="filter.key"
[label]="filter.label"
[advanced]="true"
>
<fd-combobox
*fdpValueHelpFilterDef="let filterModel"
[(ngModel)]="filterModel.value"
[dropdownValues]="booleanDropdownValues"
[placeholder]="filterModel.label"
fd-form-control
></fd-combobox>
</fdp-value-help-dialog-filter>
<fdp-value-help-dialog-filter
*ngIf="filter.key !== 'verified'"
[main]="i < 2"
[key]="filter.key"
[label]="filter.label"
[advanced]="i !== 0"
></fdp-value-help-dialog-filter>
</ng-container>
</fdp-value-help-dialog>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ExampleTestModel {
zipcode: string;
address: string;
nickname: string;
verified: string;
}

interface FilterData {
Expand All @@ -40,7 +41,8 @@ const exampleDataSource = (): { dataSource: ExampleTestModel[]; filters: FilterD
city: `City ${Math.floor(Math.random() * index)}`,
zipcode: `zipcode ${Math.floor(Math.random() * index)}`,
address: `Address ${Math.floor(Math.random() * index)}`,
nickname: `Nickname ${Math.floor(Math.random() * index)}`
nickname: `Nickname ${Math.floor(Math.random() * index)}`,
verified: Math.random() < 0.5 ? 'Yes' : 'No'
}));
return {
dataSource,
Expand All @@ -65,6 +67,8 @@ export class PlatformVhdBasicExampleComponent {

actualValue: Partial<VhdValue<ExampleTestModel>> = {};

booleanDropdownValues = ['Yes', 'No'];

actualItems: string[] = [];
formatTokenFn = (value: VhdValueChangeEvent<ExampleTestModel>): void => {
this.actualItems = [
Expand Down
10 changes: 8 additions & 2 deletions libs/docs/platform/vhd/platform-vhd-docs.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ import {
import { PlatformVhdLoadingExampleComponent } from './examples/platform-vhd-loading-example.component';
import { platformContentDensityModuleDeprecationsProvider } from '@fundamental-ngx/platform/shared';
import { PlatformVhdInitialLoadingExampleComponent } from './examples/initial-loading/platform-vhd-initial-loading-example.component';
import { PlatformVhdColumnTemplateExampleComponent } from './examples/column-template/platform-vhd-column-template-example.component';
import { ComboboxModule } from '@fundamental-ngx/core/combobox';
import { SelectModule } from '@fundamental-ngx/core/select';

const routes: Routes = [
{
Expand All @@ -55,7 +58,9 @@ const routes: Routes = [
TokenModule,
ToolbarModule,
PlatformValueHelpDialogModule,
CheckboxModule
CheckboxModule,
ComboboxModule,
SelectModule
],
exports: [RouterModule],
declarations: [
Expand All @@ -68,7 +73,8 @@ const routes: Routes = [
PlatformVhdInputExampleComponent,
PlatformVhdMobileExampleComponent,
PlatformVhdStrategyLabelExampleComponent,
PlatformVhdInitialLoadingExampleComponent
PlatformVhdInitialLoadingExampleComponent,
PlatformVhdColumnTemplateExampleComponent
],
providers: [
platformContentDensityModuleDeprecationsProvider('fdp-value-help-dialog'),
Expand Down
16 changes: 16 additions & 0 deletions libs/docs/platform/vhd/platform-vhd.docs.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,19 @@
<code-example [exampleFiles]="initialLoadingValueHelpDialog"></code-example>

<separator></separator>

<fd-docs-section-title id="custom-column" componentName="value-help-dialog">Custom columns</fd-docs-section-title>
<description>
<p>
Developers can use structural directive <code>*fdpValueHelpColumnDef</code> to define custom template to render
the column.
</p>
<p>
This example shows how to transform boolean column value into a string representation (Yes/No) with the ability
to filter by boolean values.
</p>
</description>
<component-example>
<fdp-vhd-column-template-example></fdp-vhd-column-template-example>
</component-example>
<code-example [exampleFiles]="customColumnValueHelpDialog"></code-example>
17 changes: 17 additions & 0 deletions libs/docs/platform/vhd/platform-vhd.docs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const loadingVhdTs = 'platform-vhd-loading-example.component.ts';
const initialLoadingVhdHtml = 'initial-loading/platform-vhd-initial-loading-example.component.html';
const initialLoadingVhdTs = 'initial-loading/platform-vhd-initial-loading-example.component.ts';

const customColumnVhdHtml = 'column-template/platform-vhd-column-template-example.component.html';
const customColumnVhdTs = 'column-template/platform-vhd-column-template-example.component.ts';

@Component({
selector: 'app-platform-vhd',
templateUrl: './platform-vhd.docs.component.html'
Expand Down Expand Up @@ -141,4 +144,18 @@ export class PlatformVhdDocsComponent {
fileName: 'platform-vhd-initial-loading-example'
}
];

customColumnValueHelpDialog: ExampleFile[] = [
{
language: 'html',
code: getAssetFromModuleAssets(customColumnVhdHtml),
fileName: 'platform-vhd-column-template-example'
},
{
language: 'typescript',
component: 'PlatformVhdColumnTemplateExampleComponent',
code: getAssetFromModuleAssets(customColumnVhdTs),
fileName: 'platform-vhd-column-template-example'
}
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,19 @@ <h5 fd-title role="heading" aria-level="5">
*ngFor="let filter of _tableFilters.main; let rowIndex = index"
[attr.aria-rowindex]="rowIndex"
>
{{ row[filter.key] || '' }}
<ng-container *ngIf="_columnDefMap.get(filter.key) as columnDef; else defaultColumnRenderer">
<ng-template
[ngTemplateOutlet]="columnDef.templateRef"
[ngTemplateOutletContext]="{
$implicit: row,
key: filter.key,
value: row[filter.key] || ''
}"
></ng-template>
</ng-container>
<ng-template #defaultColumnRenderer>
{{ row[filter.key] || '' }}
</ng-template>
</td>
</tr>

Expand Down
Loading

0 comments on commit 45d067b

Please sign in to comment.