From 2364ed66ff0c00966cc9dbe02b1edaa6fafb05e6 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 6 Nov 2020 18:33:13 +0100 Subject: [PATCH] Fix a bug where vscroll select lists lost content Large virtual scroll select lists lost the content after scrolling. Form values were removed from the component if the buffer was exceeding the view --- .../search-value-selector.component.html | 20 ++++++- .../search-value-selector.component.ts | 55 ++++++++++++++++--- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/client/src/app/shared/components/search-value-selector/search-value-selector.component.html b/client/src/app/shared/components/search-value-selector/search-value-selector.component.html index e3eb2ecf2..7a8739f7b 100644 --- a/client/src/app/shared/components/search-value-selector/search-value-selector.component.html +++ b/client/src/app/shared/components/search-value-selector/search-value-selector.component.html @@ -3,7 +3,17 @@ [multiple]="multiple" [panelClass]="{ 'os-search-value-selector': multiple }" [errorStateMatcher]="errorStateMatcher" + (openedChange)="openSelect($event)" > + + + + + {{ item.getTitle() | translate }}, + + + + @@ -14,7 +24,7 @@ {{ item.getTitle() | translate }} @@ -36,8 +46,12 @@ - - + + {{ selectedItem.getTitle() | translate }} diff --git a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts index e0843ad2f..4ced18806 100644 --- a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts +++ b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts @@ -1,4 +1,5 @@ import { FocusMonitor } from '@angular/cdk/a11y'; +import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { ChangeDetectionStrategy, Component, @@ -12,6 +13,7 @@ import { ViewEncapsulation } from '@angular/core'; import { FormBuilder, FormControl, NgControl } from '@angular/forms'; +import { MatOptionSelectionChange } from '@angular/material/core'; import { MatFormFieldControl } from '@angular/material/form-field'; import { TranslateService } from '@ngx-translate/core'; @@ -19,6 +21,7 @@ import { Observable } from 'rxjs'; import { auditTime } from 'rxjs/operators'; import { BaseFormControlComponentDirective } from 'app/shared/models/base/base-form-control'; +import { Identifiable } from 'app/shared/models/base/identifiable'; import { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher'; import { Selectable } from '../selectable'; @@ -55,6 +58,9 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect @ViewChild('chipPlaceholder', { static: false }) public chipPlaceholder: ElementRef; + @ViewChild(CdkVirtualScrollViewport, { static: true }) + public cdkVirtualScrollViewPort: CdkVirtualScrollViewport; + /** * Decide if this should be a single or multi-select-field */ @@ -134,6 +140,8 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect */ private selectableItems: Selectable[]; + public selectedIds: number[] = []; + public constructor( protected translate: TranslateService, formBuilder: FormBuilder, @@ -144,6 +152,13 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect super(formBuilder, focusMonitor, element, ngControl); } + public openSelect(event: boolean): void { + if (event) { + this.cdkVirtualScrollViewPort.scrollToIndex(0); + this.cdkVirtualScrollViewPort.checkViewportSize(); + } + } + /** * Function to get a list filtered by the entered search value. * @@ -167,15 +182,30 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect } } - public removeItem(itemId: number): void { - const items = this.contentForm.value; - items.splice( - items.findIndex(item => item === itemId), - 1 - ); - this.contentForm.setValue(items); + public removeChipItem(item: Selectable): void { + this.addRemoveId(item.id); } + private addRemoveId(item: number): void { + const idx = this.selectedIds.indexOf(item); + if (idx > -1) { + this.selectedIds.splice(idx, 1); + } else { + this.selectedIds.push(item); + } + this.contentForm.setValue(this.selectedIds); + } + + public onSelectionChange(change: MatOptionSelectionChange): void { + if (change.isUserInput) { + const value = change.source.value; + this.addRemoveId(value); + } + } + + /** + * Satisfy parent + */ public onContainerClick(event: MouseEvent): void { if ((event.target as Element).tagName.toLowerCase() !== 'select') { // this.element.nativeElement.querySelector('select').focus(); @@ -197,5 +227,16 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect protected updateForm(value: Selectable[] | null): void { this.contentForm.setValue(value); + if (value?.length) { + /** + * Hack: + * for loaded or preselected form, add existing values to selected IDs. + * These are usually always numbers, + * Would be easier to absolutely always use Selectable and never use IDs, + * Could save some work, but every second form has to change for that. + * -> os4 todo + */ + this.selectedIds = value as any; + } } }