Angular 9中搜索框与ngx-infinite-scroll联动失效问题
问题:Angular搜索框与ngx-infinite-scroll联动失效
使用Angular 9 + ngx-infinite-scroll组件实现搜索框与无限滚动联动,空搜索时无限滚动正常,可滚动触发loadMoreData()加载更多数据;但输入搜索内容后,scrolled事件及loadMoreData()均不触发,清空搜索框后问题仍存在。
组件代码
TypeScript代码
export class TaskMarketComponent implements OnInit, OnDestroy { @ViewChild('searchInput') searchInput!: ElementRef; @ViewChild('lastTaskCard', { read: ElementRef }) lastTaskCard!: ElementRef; public taskList: TaskDto[] = []; public filteredTaskList: TaskDto[] = []; public tasksLength: number; private isNewSearchQuery = false; private searchQuery$ = new Subject<string>(); private pageIndex = 1; private pageSize: number; private hasMoreData = true; private lastTaskId: number | null = null; searchQuery: string = ''; constructor(private taskService: TaskService) {} ngOnInit(): void { this.calculatePageSize(); this.loadTasksWithSearchResult(this.searchQuery).subscribe(r => { this.processTask(r); }) this.searchQuery$ .pipe( debounceTime(300), distinctUntilChanged(), switchMap((searchQuery) => { this.pageIndex = 1; return this.loadTasksWithSearchResult(searchQuery); }) ) .subscribe((task) => { this.taskList = []; this.processTask(task); this.setFocusOnSearchInput(); }); } ngOnDestroy(): void { this.searchQuery$.unsubscribe(); } searchTaskList(): void { this.pageIndex = 1; this.taskList = []; this.isNewSearchQuery = true this.searchQuery$.next(this.searchQuery); } private loadTasksWithSearchResult(searchQuery?: string): Observable<TaskListDto> { const filters = this.fillTasksFilters(searchQuery); return this.taskService.getTasks(filters); } private fillTasksFilters(searchQuery?: string): TaskFilterDto { return { filters: { taskId: null, recipientFullName: '', name: '', name: '', createdDate: '', executionDate: '', status: '' }, pagination: { pageNumber: this.pageIndex, pageSize: this.pageSize }, sort: { column: '', asc: true }, searchQuery: searchQuery ?? this.searchQuery }; } private setFocusOnSearchInput(): void { setTimeout(() => { if (this.searchInput) { this.searchInput.nativeElement.focus(); } }, 0); } private processTask(tasks: TaskListDto): void { tasks.data.forEach((task) => { task.TaskId = task.TaskId; }); if (tasks.data.length <= 0) { this.hasMoreData = false; } if (this.searchQuery) { this.filteredTaskList = tasks.data; } else { this.taskList = this.taskList.concat(tasks.data); this.filteredTaskList = this.taskList; } this.tasksLength = tasks.totalElements; const lastTask = tasks.data[tasks.data.length - 1]; this.lastTaskId = lastTask ? lastTask.TaskId : null; if (this.lastTaskId && !this.isNewSearchQuery) { const lastTaskCard = document.getElementById(`taskCard_${this.lastTaskId}`); if (lastTaskCard) { lastTaskCard.scrollIntoView({ behavior: 'smooth' }); } } this.isNewSearchQuery = false; this.pageIndex++; } private calculatePageSize(): void { const screenHeight = window.innerHeight; this.pageSize = Math.ceil(screenHeight / 200); } loadMoreData(): void { if (this.hasMoreData) { this.loadTasksWithSearchResult(this.searchQuery) .subscribe((task) => { this.processTask(task); }); } } }
HTML代码
<div class="tab-list-content"> <div class="row justify-content-between align-items-center table-title-row"> <div class="col-md-2 col-12 search-bar"> <input type="text" #searchInput placeholder="Search" class="form-control" [(ngModel)]="searchQuery" (ngModelChange)="searchTaskList()"/> </div> </div> <div #scrollContainer class="scroll-container" infinite-scroll (scrolled)="loadMoreData()"> <div *ngFor="let task of filteredTaskList; let last = last" class="card" [attr.id]="'taskCard_' + task.TaskId" #lastTaskCard > <div class="row card-body"> <!-- some card body --> </div> </div> </div> </div>
解决方案
1. 重置搜索相关状态
每次发起搜索(包括清空搜索)时,重置加载状态、清空结果列表,确保新查询能重新触发滚动逻辑:
searchTaskList(): void { this.pageIndex = 1; this.taskList = []; this.filteredTaskList = []; // 清空搜索结果列表 this.hasMoreData = true; // 重置加载状态 this.lastTaskId = null; // 重置最后任务ID this.isNewSearchQuery = true; this.searchQuery$.next(this.searchQuery); }
2. 修正搜索结果累加逻辑
搜索时不再直接覆盖filteredTaskList,改为累加数据,保证列表高度足够触发滚动事件:
private processTask(tasks: TaskListDto): void { tasks.data.forEach((task) => { task.TaskId = task.TaskId; }); if (tasks.data.length <= 0) { this.hasMoreData = false; } // 修改搜索结果赋值逻辑,支持累加 if (this.searchQuery) { this.filteredTaskList = [...this.filteredTaskList, ...tasks.data]; } else { this.taskList = [...this.taskList, ...tasks.data]; this.filteredTaskList = this.taskList; } this.tasksLength = tasks.totalElements; const lastTask = tasks.data[tasks.data.length - 1]; this.lastTaskId = lastTask ? lastTask.TaskId : null; if (this.lastTaskId && !this.isNewSearchQuery) { const lastTaskCard = document.getElementById(`taskCard_${this.lastTaskId}`); if (lastTaskCard) { lastTaskCard.scrollIntoView({ behavior: 'smooth' }); } } this.isNewSearchQuery = false; this.pageIndex++; }
3. 确保滚动容器样式正确
给.scroll-container添加固定高度和滚动属性,保证滚动事件能正常触发:
.scroll-container { max-height: calc(100vh - 180px); /* 根据页面布局调整高度 */ overflow-y: auto; }
4. 优化搜索管道内的状态重置(可选)
在搜索流管道中提前重置状态,避免重复逻辑:
this.searchQuery$ .pipe( debounceTime(300), distinctUntilChanged(), switchMap((searchQuery) => { this.pageIndex = 1; this.filteredTaskList = []; this.hasMoreData = true; return this.loadTasksWithSearchResult(searchQuery); }) ) .subscribe((task) => { this.taskList = []; this.processTask(task); this.setFocusOnSearchInput(); });
内容的提问来源于stack exchange,提问作者star213
相关产品推荐
相关产品推荐

