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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 19:06:06