2

我们有一个页面,其中有多个部分。每个部分可以有一张卡片或一张桌子。一个 observable 使用异步管道在 html 中绑定数据。现在我需要更新其中一个表而不刷新整个 observable。

  loadPageData(Id): void {
    this.sections$ = this.psService.getLoadPageData(Id).pipe(
      switchMap(sections => forkJoin(
        sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
          map(card => Object.assign({}, section, { card })),
          switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
            from(this.psService.getTable(this.tablePerodID).pipe(map(table => Object.assign({}, c, { table })))),
            of(c))))
        ).concatAll()
        ))
      ));
  }

  updateTable(sectionId, tablePerodID) {
    let tableData;
    this.psService.getTable(tablePerodID).subscribe((data) => {
      tableData = data;
    });
    this.sections$.forEach(sections => {
      sections.forEach(section => {
      if (section.sectionID === sectionId) {
        section.table = sectionData;
      }
    });
    });
  }

HTML就像:

<div *ngFor="let section of sections$ | async;">
  <div *ngFor="let card of section.card | sort:'displayOrder';">
    <app-card></app-card>
    <div *ngIf="card.cardTypeName === 'Table'">
      <app-table></app-table>
    </div>
   </div>
 </div>

现在的问题是当我尝试使用 updateTable [当用户更改 tablePerodID] 为表加载数据时,它什么也不做。我已经尝试过.next(),但它会更新整个section$. 无论如何我只能更新表格吗?

4

2 回答 2

3

这似乎是对管道如何运作的误解。

明喻

想想水管。

想象一下,你想要一个水龙头来倒糖水。

如果你从水龙头里取一杯水并加糖,你就不能再把水放进水龙头了。

解决方案是在您喝一杯水之前添加一根带有加糖系统的管道。

rxjs 管道是一样的,一旦你订阅,就没有回头路了。(除非您创建一个新管道并将水倒入其中;)

解决方案是通过管道传输所有内容。只有subscribe当你想获得价值时。这也有性能改进。

解决方案

this._cache$: BehaviorSubject<Section[]> = new BehaviorSubject<Section[]> ([]);
this.sections$: Observable<Section[]>;
loadPageData(id: number): void {
    // subcribe once and save the values in the cache
    this.fetchPageData(Id).subscribe(data => this._cache$.next(data));

    // section$ will emit values when caché changes
    this.sections$ = this._cache$.asObservable();
}

fetchPageData(Id): Observable<Section[]> {
    // call your data service
    return this.psService.getLoadPageData(Id).pipe(
       //...
    );
}

updateTable(sectionId, tablePerodID) {
    let tableData;
    this.psService.getTable(tablePerodID).subscribe((data) => {
      tableData = data;
    });

    this.sections$ = this.sections$.pipe(
        map(sections => sections.map(section =>
        {
            if (section.sectionID === sectionId) {
                section.table = tableData;
             }
        })
    );
}

与其订阅 observable,不如通过管道更新操作。

updateTable将更新sections$observable,html 异步管道将更新结果。

使用_cache$还有另一个性能改进,因为每次更新管道时它都不会调用您的数据服务。(没必要使用)

澄清:这将更新您的应用程序中的管道,而不是数据库或任何地方的数据。

于 2020-03-17T14:18:53.030 回答
0

感谢@adrisons 给了我缓存的想法。这是对我有用的解决方案。它与@adrisons 的回答略有不同,它不使用可观察的。

  _cached: any; 
  sections$: Observable<any>;

  loadPageData(Id): void {
    // Load data from server
    this.sections$ = this.psService.getLoadPageData(Id).pipe(
      switchMap(sections => forkJoin(
        sections.map(section => this.psService.getSectionData(section.sectionID).pipe(
          map(card => Object.assign({}, section, { card })),
          switchMap(c => c.card.map(card => iif(() => card.cardTypeId === 3,
            from(this.psService.getTable(this.tablePerodID)
            .pipe(map(table => Object.assign({}, c, { table })))),
            of(c))))
        ).concatAll()
        ))
      ), first(), // Tap and get the first emit and assign to cache
      tap((data: any) => {
        this._cached = data // Caching the data without subscribing.
      }));
  }

  updateTable(sectionId, tablePerodID) {
    // Get table Data from backend and update cache
    this.psService.getTable(tablePerodID).subscribe((data) => {
      this._cached.map(section => {
        if (section.sectionID === sectionId) {
          section.table = data;
        }
      });
    });
    // Refresh async observable from cache
    this.refreshFromCache();
  }

  refreshFromCache() {
    this.sections$ = of(this._cached)
  }
于 2020-04-01T14:04:44.497 回答