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

Angular项目Array<Array<string>>数据需点击输入框才渲染如何修复

问题根因

  • 你存在Promise与RxJS嵌套订阅混用的逻辑错误:Promise.all(promises).then执行时,内部嵌套的snap.subscribe、getLatLng.subscribe等异步回调尚未执行,此时赋值给this.matchingDocs的是空数组。你在控制台看到的有值是浏览器控制台的引用特性:打印对象时输出的是引用,展开查看时才会读取当前最新值,实际代码执行console.log的瞬间matchingDocs是空的。
  • 后续异步回调中对局部matchingDocs执行push操作时,你没有同步更新组件的this.matchingDocs,也没有触发Angular变更检测,导致视图无法响应数据更新。
  • ngOnInit中调用detectChanges无效,因为此时异步查询还未返回结果。

修复方案

方案1:快速修复现有逻辑

  1. 去掉局部的matchingDocs变量,直接操作组件的this.matchingDocs
  2. 每次push后触发变更检测
  3. 修正后的findArround代码示例:
findArround(lat: number, long: number, ray: number) {
  const geofire = require('geofire-common');
  const center = [lat, long];
  const radiusInM = ray * 20;
  const bounds = geofire.geohashQueryBounds(center, radiusInM);
  const promises = [];
  for (const b of bounds) {
    const q = this.db.collection('feeder')
    promises.push(q.get());
  }

  this.matchingDocs = []; // 先清空旧数据
  const alreadyMatched: Array<string> = [];

  Promise.all(promises).then((snapshots) => {
    for (const snap of snapshots) {
      snap.subscribe(res => {
        res.forEach(data => {
          if(alreadyMatched.includes(data.id)) return;
          
          this.feederService.getLatLng(data.id).pipe(
            switchMap(r => {
              const lat = r[0];
              const lng = r[1];
              const distanceInKm = geofire.distanceBetween([lat, lng], center);
              const distanceInM = distanceInKm * 1000;
              if (distanceInM > radiusInM) return [];
              alreadyMatched.push(data.id);
              return this.authService.getUser();
            }),
            switchMap(user => {
              const uid = this.authService.isAuth() ? user.uid : 'noUid';
              return this.feederService.getFeederById(data.id).pipe(
                map(feeder => feeder.state ? [data.id, uid] : null)
              )
            })
          ).subscribe(result => {
            if(result) {
              this.matchingDocs.push(result);
              this.changeDetection.markForCheck(); // 每次更新后触发变更检测
            }
          })
        })
      })
    }
  });
}

方案2:规范实现(推荐)

完全使用RxJS操作符整合所有异步流,避免嵌套订阅和Promise混用,等所有数据加载完成后一次性更新数据并触发变更检测,性能更好也更易维护。

import { from, forkJoin } from 'rxjs';
import { map, switchMap, filter } from 'rxjs/operators';

// 省略其他代码
findArround(lat: number, long: number, ray: number) {
  const geofire = require('geofire-common');
  const center = [lat, long];
  const radiusInM = ray * 20;
  const bounds = geofire.geohashQueryBounds(center, radiusInM);
  const alreadyMatched = new Set<string>();

  // 把所有查询转成Observable流
  const queryStreams = bounds.map(b => from(this.db.collection('feeder').get()));

  forkJoin(queryStreams).pipe(
    // 展开所有查询结果
    map(snapshots => snapshots.flatMap(snap => snap.docs)),
    // 逐个处理每个文档
    switchMap(docs => {
      const docStreams = docs.map(data => {
        if(alreadyMatched.has(data.id)) return [];
        return this.feederService.getLatLng(data.id).pipe(
          filter(r => {
            const distanceInM = geofire.distanceBetween([r[0], r[1]], center) * 1000;
            return distanceInM <= radiusInM;
          }),
          switchMap(() => {
            alreadyMatched.add(data.id);
            return this.authService.getUser();
          }),
          switchMap(user => {
            const uid = this.authService.isAuth() ? user.uid : 'noUid';
            return this.feederService.getFeederById(data.id).pipe(
              map(feeder => feeder.state ? [data.id, uid] : null)
            )
          }),
          filter(res => !!res)
        )
      })
      return forkJoin(docStreams);
    })
  ).subscribe(results => {
    this.matchingDocs = results.filter(r => !!r);
    this.changeDetection.detectChanges(); // 一次性触发变更检测
  })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:54:01