【问题标题】:Angular ng-select virtual scroll functionalityAngular ng-select 虚拟滚动功能
【发布时间】:2020-05-22 05:17:15
【问题描述】:

我的页面包含多个由 *ngFor 指令创建的 ng-select(自定义服务器端搜索)下拉列表,可以从每个下拉列表中选择多个项目。

我还想包含virtual scroll 功能,但我不知道如何发出另一个服务器请求并更新filterValues$ 值以包含新数据。

component.html

<ng-select [items]="filterValues$[filter.name] | async"
         [typeahead]="filterValuesInput$[filter.name]"
         [virtualScroll]="true"
         [multiple]="true"
         [closeOnSelect]="false"
         [loading]="filterValuesLoading[filter.name]"
         [(ngModel)]="filter.filter_values"
         (scrollToEnd)="onScrollToEnd(filter.name)"
         (open)="onFilterOpen(filter.name)"
         typeToSearchText="No values found"
         bindLabel="name">
</ng-select>

component.ts

onScrollToEnd(filterName) {
    this.fetchMore(filterName);
}

fetchMore(filterName) {
    this.filterValues$[filterName] = combineLatest(this.getFilterValues(filterName, this.afterKey), of(this.existingValues))
      .pipe(
        map(combined => {
          return combined[1].concat(combined[0])
        })
    );
}

getFilterValues(filterName, after) {
    return this.filterValuesInput$[filterName].pipe(
      tap(() => this.filterValuesLoading[filterName] = true),
      startWith(''),
      distinctUntilChanged(),
      switchMap(term  => this.search.getFilterValues(filterName, '' + term, '' + after).pipe(
        tap(res => {
          this.afterKey = res.after_key;
          this.filterValuesLoading[filterName] = false;
          this.existingValues = this.existingValues.concat(res.filter_values);
          this.totalFilterValues = res.total_hits;
          //this.bufferLength += this.initialValues.length;
        }),
        map(res => res.filter_values),
        catchError(() => of([])) // empty list on error
      ))
    )
}

任何帮助将不胜感激!

使用更新的代码进行编辑:我设法实现了虚拟滚动功能,但是每当我进入下拉列表的底部时,它都会触发 fetchMore() 方法并重置 this.filterValues$[filterName] 值,从而将下拉列表从底部移动到顶部。我怎样才能防止这种情况发生?

【问题讨论】:

  • 我注意到的唯一问题是,您没有订阅 fetchMore 结果。如果没有工作示例,很难找出问题。在stackblitz.com 上创建此类
  • 请检查我更新的问题。不幸的是,我无法创建堆栈闪电战。
  • 尝试设置[trackByFn]功能。这将有助于 ng-select 管理更改的项目并可能解决您的问题

标签: angular rxjs angular-ngselect virtualscroll


【解决方案1】:

我遇到了同样的问题。

问题是 ng-select 尝试查找所选值的选项,该选项在第一次加载时可能不可用。例如,您正在加载前 15 个值,但所选选项位于后面的位置,即使您 fetchMore 它可能仍然不在下一次提取中。因此,如果您调用 next,它会将您设置到下拉列表的第一个位置。

如果您使用鼠标滚轮滚动,这可能不是问题,因为它会自动聚焦在您的鼠标光标所在的位置。 但是如果你使用箭头,它总是会跳到开头(这是我的问题)。

我的解决方案是始终在选项列表的开头添加一个附加选项(选定的选项)(以便 ng-select 可以找到它)+ 列表的其余部分。 该选项可能会在列表中重复,但它的用户友好性是让列表中的第一个选项成为最初选择的选项。

请注意,我使用的是 ControlValueAccessor。

  protected _itemsBufferSource$ = new BehaviorSubject<unknown[]>([]);    
  public items$: Observable<unknown[]> = EMPTY;
  public input$ = new Subject<string>();
  public virtualScrollItems: unknown[] = [];
  public itemsBuffer$: Observable<unknown[]> = this._itemsBufferSource$.asObservable();

<ng-select
  #singleSelect
  [items]="(enableVirtualScrolling ? this.itemsBuffer$ : this.items$) | async"
  ...
  [(ngModel)]="valueChanged"
...

const firstValue:unknown[] = [this.valueChanged];
...
this._itemsBufferSource$.next(
          //add first value to beginning so it would find selected value and arrow virtual scrolling would work(filter out the nulls so there's no error)
          firstValue.concat(this.virtualScrollItems.slice(0, this.virtualScrollingBufferSize)).filter(x => x != null));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-08
    • 2019-08-03
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    相关资源
    最近更新 更多