You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中ng-select滚动触底加载更多选项失效问题求助

问题分析与解决方案

核心问题

  1. 滚动事件绑定对象错误:你把scroll事件绑在了包裹ng-select的div上,但因为设置了appendTo="body",ng-select的下拉列表会被渲染到body节点下,完全脱离了这个div,所以滚动下拉列表时根本不会触发div的scroll事件。
  2. 数据绑定逻辑错误:ng-select的[items]绑定的是extractedOptions,但你每次加载新数据后是把新选项追加到options数组,这会导致下拉列表只显示最后一次加载的10条,而非所有已加载的选项。
  3. 重复加载风险:没有判断加载状态和剩余数据量,可能导致多次重复请求。

具体修复步骤

1. 修正数据绑定

将ng-select的[items]从extractedOptions改为options,确保下拉列表显示所有已加载的选项:

<ng-select
  formControlName="device_id"
  [items]="options" <!-- 此处修改 -->
  bindLabel="label"
  bindValue="value"
  placeholder="Select device"
  appendTo="body"
  [multiple]="true"
>
  <ng-template ng-label-tmp let-item="item">
    {{ item.label }}
  </ng-template>
  <ng-template ng-option-tmp let-item="item" let-search="searchTerm" let-index="index">
    {{ item.label }}
  </ng-template>
  <!-- 添加加载状态提示 -->
  <ng-template ng-footer-tmp>
    <div *ngIf="loading" style="text-align: center; padding: 8px;">
      加载中...
    </div>
  </ng-template>
</ng-select>

2. 监听下拉面板的滚动事件

首先导入NgSelectComponent,通过组件实例监听下拉面板的滚动:

import { NgSelectComponent } from '@ng-select/ng-select';
// ...其他导入

@Component({
  selector: 'app-create-device',
  templateUrl: './create-device.component.html',
  styleUrls: ['./create-device.component.scss'],
})
export class DeviceComponent {
  @ViewChild(NgSelectComponent) deviceSelect!: NgSelectComponent;
  private scrollListener?: () => void;
  // ...其他属性

  ngAfterViewInit() {
    // 下拉面板打开时绑定滚动监听
    this.deviceSelect.opened.subscribe(() => {
      const dropdownPanel = document.querySelector('.ng-dropdown-panel');
      if (dropdownPanel && !this.scrollListener) {
        this.scrollListener = () => this.onDropdownScroll(dropdownPanel as HTMLElement);
        dropdownPanel.addEventListener('scroll', this.scrollListener);
      }
    });

    // 下拉面板关闭时移除监听,避免内存泄漏
    this.deviceSelect.closed.subscribe(() => {
      if (this.scrollListener) {
        const dropdownPanel = document.querySelector('.ng-dropdown-panel');
        dropdownPanel?.removeEventListener('scroll', this.scrollListener);
        this.scrollListener = undefined;
      }
    });
  }
}

3. 实现滚动加载逻辑

替换原有的onScroll方法,添加加载状态和剩余数据判断:

onDropdownScroll(target: HTMLElement) {
  // 避免加载中重复请求,或数据已全部加载完成
  if (this.loading || this.options.length >= this.totalCount) {
    return;
  }

  // 滚动到接近底部(留10px阈值)时触发加载
  if (target.offsetHeight + target.scrollTop >= target.scrollHeight - 10) {
    this.loadOptions();
  }
}

4. 修正数据加载逻辑

简化loadOptions中的数组处理,保持数据不可变性,并添加错误处理:

loadOptions() {
  this.loading = true;
  this.deviceService.getData(this.items_per_page, this.page).subscribe((response: any) => {
    const records = response.data.records;
    this.totalCount = response.data.count.total;
    const newOptions = records.map((record: any) => ({
      label: record.name,
      value: record.id,
    }));

    this.options = [...this.options, ...newOptions]; // 扩展运算符追加新选项
    this.page++;
    this.loading = false;
  }, (error) => {
    this.loading = false;
    this._snackBar.open('加载设备数据失败', '关闭', { duration: 3000 });
  });
}

5. 清理无用代码

  • 删除包裹ng-select的div上的(scroll)="onScroll($event)"属性
  • 删除组件中的@HostListener('scroll',['$event'])装饰器和原onScroll方法

内容的提问来源于stack exchange,提问作者Naman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:58:08