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
This commit is contained in:
parent
5b84bddc2a
commit
2364ed66ff
@ -3,7 +3,17 @@
|
|||||||
[multiple]="multiple"
|
[multiple]="multiple"
|
||||||
[panelClass]="{ 'os-search-value-selector': multiple }"
|
[panelClass]="{ 'os-search-value-selector': multiple }"
|
||||||
[errorStateMatcher]="errorStateMatcher"
|
[errorStateMatcher]="errorStateMatcher"
|
||||||
|
(openedChange)="openSelect($event)"
|
||||||
>
|
>
|
||||||
|
<!-- Custom display of selected items -->
|
||||||
|
<mat-select-trigger>
|
||||||
|
<ng-container *ngIf="selectedItems?.length">
|
||||||
|
<span *ngFor="let item of selectedItems; let i = index">
|
||||||
|
{{ item.getTitle() | translate }}<span *ngIf="i < selectedItems.length - 1">, </span>
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
</mat-select-trigger>
|
||||||
|
|
||||||
<mat-option>
|
<mat-option>
|
||||||
<ngx-mat-select-search [formControl]="searchValue"></ngx-mat-select-search>
|
<ngx-mat-select-search [formControl]="searchValue"></ngx-mat-select-search>
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@ -14,7 +24,7 @@
|
|||||||
<mat-chip
|
<mat-chip
|
||||||
*ngFor="let item of selectedItems"
|
*ngFor="let item of selectedItems"
|
||||||
[removable]="true"
|
[removable]="true"
|
||||||
(removed)="removeItem(item.id)"
|
(removed)="removeChipItem(item)"
|
||||||
[disableRipple]="true"
|
[disableRipple]="true"
|
||||||
>
|
>
|
||||||
{{ item.getTitle() | translate }}
|
{{ item.getTitle() | translate }}
|
||||||
@ -36,8 +46,12 @@
|
|||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<cdk-virtual-scroll-viewport class="vscroll-viewport" minBufferPx="200" maxBufferPx="300" [itemSize]="50">
|
<cdk-virtual-scroll-viewport class="vscroll-viewport" minBufferPx="400" maxBufferPx="600" [itemSize]="50">
|
||||||
<mat-option *cdkVirtualFor="let selectedItem of getFilteredItems()" [value]="selectedItem.id">
|
<mat-option
|
||||||
|
*cdkVirtualFor="let selectedItem of getFilteredItems()"
|
||||||
|
[value]="selectedItem.id"
|
||||||
|
(onSelectionChange)="onSelectionChange($event)"
|
||||||
|
>
|
||||||
{{ selectedItem.getTitle() | translate }}
|
{{ selectedItem.getTitle() | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</cdk-virtual-scroll-viewport>
|
</cdk-virtual-scroll-viewport>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FocusMonitor } from '@angular/cdk/a11y';
|
import { FocusMonitor } from '@angular/cdk/a11y';
|
||||||
|
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
@ -12,6 +13,7 @@ import {
|
|||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormBuilder, FormControl, NgControl } from '@angular/forms';
|
import { FormBuilder, FormControl, NgControl } from '@angular/forms';
|
||||||
|
import { MatOptionSelectionChange } from '@angular/material/core';
|
||||||
import { MatFormFieldControl } from '@angular/material/form-field';
|
import { MatFormFieldControl } from '@angular/material/form-field';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -19,6 +21,7 @@ import { Observable } from 'rxjs';
|
|||||||
import { auditTime } from 'rxjs/operators';
|
import { auditTime } from 'rxjs/operators';
|
||||||
|
|
||||||
import { BaseFormControlComponentDirective } from 'app/shared/models/base/base-form-control';
|
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 { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher';
|
||||||
import { Selectable } from '../selectable';
|
import { Selectable } from '../selectable';
|
||||||
|
|
||||||
@ -55,6 +58,9 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect
|
|||||||
@ViewChild('chipPlaceholder', { static: false })
|
@ViewChild('chipPlaceholder', { static: false })
|
||||||
public chipPlaceholder: ElementRef<HTMLElement>;
|
public chipPlaceholder: ElementRef<HTMLElement>;
|
||||||
|
|
||||||
|
@ViewChild(CdkVirtualScrollViewport, { static: true })
|
||||||
|
public cdkVirtualScrollViewPort: CdkVirtualScrollViewport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decide if this should be a single or multi-select-field
|
* Decide if this should be a single or multi-select-field
|
||||||
*/
|
*/
|
||||||
@ -134,6 +140,8 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect
|
|||||||
*/
|
*/
|
||||||
private selectableItems: Selectable[];
|
private selectableItems: Selectable[];
|
||||||
|
|
||||||
|
public selectedIds: number[] = [];
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
formBuilder: FormBuilder,
|
formBuilder: FormBuilder,
|
||||||
@ -144,6 +152,13 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect
|
|||||||
super(formBuilder, focusMonitor, element, ngControl);
|
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.
|
* 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 {
|
public removeChipItem(item: Selectable): void {
|
||||||
const items = <number[]>this.contentForm.value;
|
this.addRemoveId(item.id);
|
||||||
items.splice(
|
|
||||||
items.findIndex(item => item === itemId),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
this.contentForm.setValue(items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
public onContainerClick(event: MouseEvent): void {
|
||||||
if ((event.target as Element).tagName.toLowerCase() !== 'select') {
|
if ((event.target as Element).tagName.toLowerCase() !== 'select') {
|
||||||
// this.element.nativeElement.querySelector('select').focus();
|
// this.element.nativeElement.querySelector('select').focus();
|
||||||
@ -197,5 +227,16 @@ export class SearchValueSelectorComponent extends BaseFormControlComponentDirect
|
|||||||
|
|
||||||
protected updateForm(value: Selectable[] | null): void {
|
protected updateForm(value: Selectable[] | null): void {
|
||||||
this.contentForm.setValue(value);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user