Angular中ng-select滚动触底加载更多选项失效问题求助
问题分析与解决方案
核心问题
- 滚动事件绑定对象错误:你把
scroll事件绑在了包裹ng-select的div上,但因为设置了appendTo="body",ng-select的下拉列表会被渲染到body节点下,完全脱离了这个div,所以滚动下拉列表时根本不会触发div的scroll事件。 - 数据绑定逻辑错误:
ng-select的[items]绑定的是extractedOptions,但你每次加载新数据后是把新选项追加到options数组,这会导致下拉列表只显示最后一次加载的10条,而非所有已加载的选项。 - 重复加载风险:没有判断加载状态和剩余数据量,可能导致多次重复请求。
具体修复步骤
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
相关产品推荐
相关产品推荐

