Angular 搜索栏发起API请求时显示加载spinner的实现问题求助
实现方案
你需要调整两处核心逻辑:一是触发搜索时立即开启加载状态,二是等所有搜索相关的API请求全部完成后再关闭加载状态,同时要处理请求异常场景避免spinner一直显示。
第一步:修改ts文件代码
// 顶部先导入需要的rxjs工具 import { forkJoin, Subscription } from 'rxjs'; import { finalize } from 'rxjs/operators'; @Component({ selector: 'app-orders-list', templateUrl: './orders-list.component.html', styleUrls: ['./orders-list.component.css'], }) export class OrdersListComponent implements OnChanges, AfterViewInit, OnDestroy{ @Input() ordersWithSlots: Order[] = []; @Input() ordersWithNoSlots: Order[] = []; @Input() timelinesWithSlots: string[] = []; @Input() timelinesWithNoSlots: string[] = []; @Input() currentTabIndex: number; @Input() searchTerm: string; filteredSlotsOrders: Order[] = []; filteredNoSlotsOrders: Order[] = [] filteredSlotsTimelines: string[] = []; filteredNoSlotsTimelines: string[] = []; showSpinner = false; // 新增变量存储搜索请求订阅,处理连续搜索的竞态问题 private searchSub: Subscription; constructor( private apiManager: ApiManagerService, private ordersService: OrdersManagerService ) {} ngOnChanges(changes: SimpleChanges): void { // searchTerm comes from parent component, if it changes then a new search is active if (changes.searchTerm) { if(changes.searchTerm.currentValue !== changes.searchTerm.previousValue){ if(changes.searchTerm.currentValue === "") { this.filteredSlotsOrders = [...this.ordersWithSlots]; this.filteredNoSlotsOrders = [...this.ordersWithNoSlots]; this.filteredSlotsTimelines = [...this.timelinesWithSlots]; this.filteredNoSlotsTimelines = [...this.timelinesWithNoSlots]; } else{ // 开启加载状态 this.showSpinner = true; // 取消未完成的旧搜索请求,避免旧结果覆盖新结果 if(this.searchSub) this.searchSub.unsubscribe(); this.getOrdersBySearchTerm(); } } } ... } getOrdersBySearchTerm(){ if(this.currentTabIndex === 0){ // 用forkJoin合并两个并行请求,等所有请求返回后再处理结果 this.searchSub = forkJoin({ slotsOrders: this.apiManager.fetchOrdersBySearchTerm("status=PENDING&status=FULFILLED&only_slots=true", this.searchTerm), allOrders: this.apiManager.fetchOrdersBySearchTerm("status=PENDING&status=FULFILLED", this.searchTerm) }).pipe( // 无论请求成功/失败,最终都关闭加载状态 finalize(() => this.showSpinner = false) ).subscribe({ next: (res) => { this.filteredSlotsOrders = res.slotsOrders.results; const loadedAllOrders = res.allOrders.results; this.filteredNoSlotsOrders = this.ordersService.filterOrders(loadedAllOrders, OrderStatus.PENDING, false); this.filteredNoSlotsOrders = [...this.filteredNoSlotsOrders, ...this.ordersService.filterOrders(loadedAllOrders, OrderStatus.PROCESSED, false)] }, error: (err) => { // 这里可自行添加错误提示逻辑 console.error('搜索失败', err) } }) } ... } // 组件销毁时取消未完成的请求 ngOnDestroy() { if(this.searchSub) this.searchSub.unsubscribe(); } }
第二步:优化html代码(可选,写法更直观)
<app-loading-spinner *ngIf="showSpinner"></app-loading-spinner> <div *ngIf="!showSpinner"> <!-- 原有视图内容 --> </div>
调整后只有触发搜索请求时才会显示spinner,不会影响页面初始加载的展示逻辑,也避免了请求失败后spinner一直显示的问题。
内容的提问来源于stack exchange,提问作者Manuel Brás
相关产品推荐
相关产品推荐

