From b5abdaae073dac5d976a2f642a4a43dd789e1cb0 Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Fri, 6 Jun 2025 20:50:12 +0200 Subject: [PATCH] Feature/extend GfSymbolAutocompleteComponent by default options (#4563) * Extend GfSymbolAutocompleteComponent by default options * Update changelog --- CHANGELOG.md | 1 + libs/ui/src/lib/mocks/httpClient.mock.ts | 18 +++ .../symbol-autocomplete.component.html | 2 +- .../symbol-autocomplete.component.stories.ts | 115 ++++++++++++++++++ .../symbol-autocomplete.component.ts | 38 ++++-- 5 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 libs/ui/src/lib/mocks/httpClient.mock.ts create mode 100644 libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 55cb91e29..1d71729b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Extended the symbol search component by default options - Improved the language localization for Spanish (`es`) - Upgraded `ng-extract-i18n-merge` from version `2.15.0` to `2.15.1` - Upgraded `Nx` from version `20.8.1` to `21.1.2` diff --git a/libs/ui/src/lib/mocks/httpClient.mock.ts b/libs/ui/src/lib/mocks/httpClient.mock.ts new file mode 100644 index 000000000..6ef79af61 --- /dev/null +++ b/libs/ui/src/lib/mocks/httpClient.mock.ts @@ -0,0 +1,18 @@ +import { Observable } from 'rxjs'; + +export class HttpClientMock { + public constructor(private mockResponses: Map) {} + + public get(url: string, options?: any): Observable { + if (this.mockResponses.has(url) && options) { + return new Observable((subscriber) => { + subscriber.next(this.mockResponses.get(url)); + subscriber.complete(); + }); + } + + return new Observable((subscriber) => { + subscriber.error(new Error(`No mock data for URL: ${url}`)); + }); + } +} diff --git a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html index c6327c318..456cd9940 100644 --- a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html +++ b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html @@ -12,7 +12,7 @@ (optionSelected)="onUpdateSymbol($event)" > @if (!isLoading) { - @for (lookupItem of filteredLookupItems; track lookupItem) { + @for (lookupItem of lookupItems; track lookupItem) { ; + +type Story = StoryObj; + +export const Default: Story = { + args: {} +}; + +export const WithDefaultItems: Story = { + args: { + defaultLookupItems: DEFAULT_OPTIONS + } +}; diff --git a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts index 3c56c4748..4d73e3c53 100644 --- a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts +++ b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts @@ -76,16 +76,17 @@ export class GfSymbolAutocompleteComponent extends AbstractMatFormField implements OnInit, OnDestroy { - @Input() private includeIndices = false; + @Input() public defaultLookupItems: LookupItem[] = []; @Input() public isLoading = false; - @ViewChild(MatInput) private input: MatInput; - @ViewChild('symbolAutocomplete') public symbolAutocomplete: MatAutocomplete; + @Input() private includeIndices = false; + + @ViewChild(MatInput) private input: MatInput; + public control = new FormControl(); - public filteredLookupItems: (LookupItem & { assetSubClassString: string })[] = - []; + public lookupItems: (LookupItem & { assetSubClassString: string })[] = []; private unsubscribeSubject = new Subject(); @@ -106,6 +107,10 @@ export class GfSymbolAutocompleteComponent this.control.disable(); } + if (this.defaultLookupItems?.length) { + this.showDefaultOptions(); + } + this.control.valueChanges .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { @@ -117,7 +122,13 @@ export class GfSymbolAutocompleteComponent this.control.valueChanges .pipe( filter((query) => { - return isString(query) && query.length > 1; + if (query.length === 0) { + this.showDefaultOptions(); + + return false; + } + + return isString(query); }), tap(() => { this.isLoading = true; @@ -135,7 +146,7 @@ export class GfSymbolAutocompleteComponent }) ) .subscribe((filteredLookupItems) => { - this.filteredLookupItems = filteredLookupItems.map((lookupItem) => { + this.lookupItems = filteredLookupItems.map((lookupItem) => { return { ...lookupItem, assetSubClassString: translate(lookupItem.assetSubClass) @@ -161,7 +172,7 @@ export class GfSymbolAutocompleteComponent } public isValueInOptions(value: string) { - return this.filteredLookupItems.some((item) => { + return this.lookupItems.some((item) => { return item.symbol === value; }); } @@ -193,6 +204,17 @@ export class GfSymbolAutocompleteComponent this.unsubscribeSubject.complete(); } + private showDefaultOptions() { + this.lookupItems = this.defaultLookupItems.map((lookupItem) => { + return { + ...lookupItem, + assetSubClassString: translate(lookupItem.assetSubClass) + }; + }); + + this.changeDetectorRef.markForCheck(); + } + private validateRequired() { const requiredCheck = super.required ? !super.value?.dataSource || !super.value?.symbol