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

ng-select无法从服务获取数据,仅添加延迟后可正常工作

ng-select无法订阅Observable,仅加delay后显示数据的解决方案

问题描述

使用ng-select实现活动搜索选择功能:用户输入内容时触发服务调用,服务返回匹配的活动数组Observable,ng-select通过async管道订阅该Observable。但ng-select无法正常获取数据,只有给服务返回的Observable添加pipe(delay(100))时才能显示数据,移除延迟后控制台能打印正确数组,但ng-select就是不渲染。

相关代码

HTML代码

<label for="class">Activité</label>
<ng-select [items]="activities$ | async"
           groupBy="type"
           [(ngModel)]="selectedActivity"
           [ngModelOptions]="{standalone: true}" 
           (search)="inputChanged($event)">
</ng-select>

组件TypeScript代码

activities$!: Observable<Activity[]>;
selectedActivity!: Activity;

private modelChanged: Subject<string> = new Subject<string>();
private searchSubscription!: Subscription;
debounceTime = 500;

constructor(private dataService: DataService) { }

ngOnInit(): void {
  this.initActivitySearchListener();
};

initActivitySearchListener(): void {
   this.searchSubscription = this.modelChanged
      .pipe(
        debounceTime(this.debounceTime),
      )
      .subscribe(input => {
        console.log(input)
        this.updateSearch(input);
   });
}

//输入活动搜索框时触发
inputChanged($event: any) {
   this.modelChanged.next($event.term);
}

updateSearch(term: string) {
   console.log(term);
   this.activities$ = this.dataService.getActivitiesForList(term);
   this.dataService.getActivitiesForList(term).subscribe(data => console.log(data));
}

服务TypeScript代码

getActivitiesForList(inputString: string): Observable<Activity[]> {

    let parsedResult: Activity[] = [];

    this.http.get<any>(this.HOST + this.API_URI + 'activity?searchText=' + inputString).subscribe((data) => {
      for (const activity of data) {
        switch (activity.type) {
          case "dungeon":
            let tempBossArray: any[] = [];
            activity.dungeon_boss.forEach((bossObject: any) => {
              tempBossArray.push(bossObject.name);
            });
            parsedResult.push({ id: activity.id, name: activity.name + ' (' + tempBossArray.toString() + ') ' + '[Niv. ' + activity.level + ']', type: "Donjon" });
            break;

          case "quest":
            parsedResult.push({ id: activity.id, name: activity.name + ' (' + activity.category + ')', type: "Quête" });
            break;

          default:
            break;
        }
      }
    });
    return of(parsedResult).pipe(delay(100));
  };

问题根源

服务的getActivitiesForList方法逻辑错误:

  • 直接订阅了http.get请求,然后同步返回of(parsedResult),此时HTTP请求还没完成,parsedResult是空数组。
  • 添加delay(100)只是巧合让HTTP请求在延迟结束前完成,填充了数组,属于不可靠的临时解决方案。

修复方案

1. 重构服务方法,用RxJS操作符处理数据流

不要手动订阅HTTP请求,改用map操作符在响应返回后处理数据,返回的Observable会正确发出处理后的结果:

getActivitiesForList(inputString: string): Observable<Activity[]> {
  // 用模板字符串拼接URL更简洁
  return this.http.get<any>(`${this.HOST}${this.API_URI}activity?searchText=${inputString}`).pipe(
    map(data => {
      const parsedResult: Activity[] = [];
      for (const activity of data) {
        switch (activity.type) {
          case "dungeon":
            // 用map替代forEach简化数组处理
            const tempBossArray = activity.dungeon_boss.map((bossObject: any) => bossObject.name);
            parsedResult.push({ 
              id: activity.id, 
              name: `${activity.name} (${tempBossArray.toString()}) [Niv. ${activity.level}]`, 
              type: "Donjon" 
            });
            break;
          case "quest":
            parsedResult.push({ 
              id: activity.id, 
              name: `${activity.name} (${activity.category})`, 
              type: "Quête" 
            });
            break;
          default:
            break;
        }
      }
      return parsedResult;
    })
  );
}

2. 优化组件订阅逻辑(可选但更规范)

组件中无需手动订阅服务返回的Observable,async管道会自动处理订阅和取消订阅,避免内存泄漏:

updateSearch(term: string) {
  console.log(term);
  this.activities$ = this.dataService.getActivitiesForList(term);
  // 删除手动订阅的代码
  // this.dataService.getActivitiesForList(term).subscribe(data => console.log(data));
}

修复原理

  • 服务返回的Observable会在HTTP请求完成、数据处理完毕后才发出值,async管道能正确接收到并更新ng-select的items。
  • 去掉delay后,数据流依然是异步的,ng-select会在数据准备好时自动渲染,无需依赖延迟的巧合。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:35:19