From 4bbfb4cc1a5b4e7cadf6b2e9be1d89f9873901cd Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Thu, 4 Jan 2024 17:29:28 +0100 Subject: [PATCH 1/6] 110088: new implementation for keyboard support in dropdowns --- .../dynamic-scrollable-dropdown.component.ts | 83 +++++++++++++------ 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts index a4ca2101934..26797f6e045 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts @@ -40,6 +40,8 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom public loading = false; public pageInfo: PageInfo; public optionsList: any; + public inputText: string = null; + public acceptableKeys = ['Space', 'NumpadMultiply', 'NumpadAdd', 'NumpadSubtract', 'NumpadDecimal', 'Semicolon', 'Equal', 'Comma', 'Minus', 'Period', 'Quote', 'Backquote']; constructor(protected vocabularyService: VocabularyService, protected cdr: ChangeDetectorRef, @@ -54,32 +56,25 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom */ ngOnInit() { this.updatePageInfo(this.model.maxOptions, 1); - this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe( + this.loadOptions(); + } + + loadOptions() { + this.loading = true; + this.vocabularyService.getVocabularyEntriesByValue(this.inputText, false, this.model.vocabularyOptions, this.pageInfo).pipe( getFirstSucceededRemoteDataPayload(), - catchError(() => observableOf(buildPaginatedList( - new PageInfo(), - [] - )) - )) - .subscribe((list: PaginatedList) => { - this.optionsList = list.page; - if (this.model.value) { - this.setCurrentValue(this.model.value, true); - } - - this.updatePageInfo( - list.pageInfo.elementsPerPage, - list.pageInfo.currentPage, - list.pageInfo.totalElements, - list.pageInfo.totalPages - ); - this.cdr.detectChanges(); - }); - - this.group.get(this.model.id).valueChanges.pipe(distinctUntilChanged()) - .subscribe((value) => { - this.setCurrentValue(value); - }); + catchError(() => observableOf(buildPaginatedList(new PageInfo(), []))), + tap(() => this.loading = false) + ).subscribe((list: PaginatedList) => { + this.optionsList = list.page; + this.updatePageInfo( + list.pageInfo.elementsPerPage, + list.pageInfo.currentPage, + list.pageInfo.totalElements, + list.pageInfo.totalPages + ); + this.cdr.detectChanges(); + }); } /** @@ -94,6 +89,8 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom openDropdown(sdRef: NgbDropdown) { if (!this.model.readOnly) { this.group.markAsUntouched(); + this.inputText = null; + this.loadOptions(); sdRef.open(); } } @@ -112,7 +109,41 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom sdRef.toggle(); } else if (keyName === 'ArrowDown' || keyName === 'ArrowUp') { this.openDropdown(sdRef); + } else if (keyName === 'Backspace') { + this.removeKeyFromInput(); + } else if (this.isAcceptableKey(keyName)) { + this.addKeyToInput(keyName); + } + } + + addKeyToInput(keyName: string) { + if (this.inputText === null) { + this.inputText = ''; + } + this.inputText += keyName; + // When a new key is added, we need to reset the page info + this.updatePageInfo(this.model.maxOptions, 1); + this.loadOptions(); + } + + removeKeyFromInput() { + if (this.inputText !== null) { + this.inputText = this.inputText.slice(0, -1); + if (this.inputText === '') { + this.inputText = null; + } + this.loadOptions(); + } + } + + + isAcceptableKey(keyPress: string): boolean { + // allow all letters and numbers + if (keyPress.length == 1 && keyPress.match(/^[a-zA-Z0-9]*$/)) { + return true; } + // Some other characters like space, dash, etc should be allowed as well + return this.acceptableKeys.includes(keyPress); } /** @@ -127,7 +158,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom this.pageInfo.totalElements, this.pageInfo.totalPages ); - this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe( + this.vocabularyService.getVocabularyEntriesByValue(this.inputText, false, this.model.vocabularyOptions, this.pageInfo).pipe( getFirstSucceededRemoteDataPayload(), catchError(() => observableOf(buildPaginatedList( new PageInfo(), From 74f1c613f66c25a5af0fbd1ccc476baa4290efdc Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Thu, 4 Jan 2024 17:40:08 +0100 Subject: [PATCH 2/6] 110088: lint issue --- .../dynamic-scrollable-dropdown.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts index 26797f6e045..6c864f90b12 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } fro import { UntypedFormGroup } from '@angular/forms'; import { Observable, of as observableOf } from 'rxjs'; -import { catchError, distinctUntilChanged, map, tap } from 'rxjs/operators'; +import { catchError, map, tap } from 'rxjs/operators'; import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'; import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; @@ -139,7 +139,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom isAcceptableKey(keyPress: string): boolean { // allow all letters and numbers - if (keyPress.length == 1 && keyPress.match(/^[a-zA-Z0-9]*$/)) { + if (keyPress.length === 1 && keyPress.match(/^[a-zA-Z0-9]*$/)) { return true; } // Some other characters like space, dash, etc should be allowed as well From 3a265bb0e7c6743a007a666abedad1f6695e48b0 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Wed, 10 Jan 2024 11:03:36 +0100 Subject: [PATCH 3/6] 110088: reset pagination on opening of dropdown --- .../scrollable-dropdown/dynamic-scrollable-dropdown.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts index 6c864f90b12..ce481351fd9 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts @@ -90,6 +90,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom if (!this.model.readOnly) { this.group.markAsUntouched(); this.inputText = null; + this.updatePageInfo(this.model.maxOptions, 1); this.loadOptions(); sdRef.open(); } From 05eb21250efcbe94fbb174d35bf170663a0d8b13 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Mon, 22 Jan 2024 15:06:57 +0100 Subject: [PATCH 4/6] 110088: changes to keyboard navigation / selection --- ...dynamic-scrollable-dropdown.component.html | 5 ++- .../dynamic-scrollable-dropdown.component.ts | 45 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index 1ac38e9943c..60fba046877 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -26,7 +26,7 @@ (keydown)="selectOnKeyDown($event, sdRef)"> -