首页 > 解决方案 > 有角度的多个流,一个可观察的

问题描述

我有基于特定日期从服务器中提取的数据。因此,当日期更改时,我再次从服务器查询以获取新数据。我还可以从服务器手动触发刷新(对于我从中提取数据的情况,因此我需要重新提取)

private _date = new BehaviorSubject(new Date())
private _refresh = new BehaviorSubject<void>(undefined); 
readonly data$: Observable<Model[]> = combineLatest([this._date, this._refresh])
   .pipe( 
      switchMap(([date, refresh]) => this.dataService.get(date)),
      shareReplay(1) 
   )

我的视图正在data$使用异步管道显示

我需要能够操作列表,data$以便跟踪列表中修改的项目。

Model {
   ...
   isModified: boolean
}

我的模型是这样的,所以如果我对元素进行更改,我希望能够将其推送到数据列表中(删除旧项目-> 替换为新修改的项目)然后data$发出更新列表。

然后,如果_date发射器$data会发射它,那么所有修改过的东西都会被清除。

我试图不直接改变列表中的项目,以便我可以利用ChangeDetectionStrategy.OnPush

有没有一种方法可以结合手动更新列表和_date更新列表的流程,但是当从服务器拉取优先时。


只维护一个列表应该可以让我更容易地根据数据获取聚合。随着项目的更新,我的汇总值将根据修改后的列表进行更新。如果我维护了第二个修改项目列表,我需要比较这两个列表,如果我希望聚合值处于修改状态(获取主列表中未修改的所有项目以及修改列表中的所有项目)。

批量更新应该就像

data$.pipe(
   filter(x => x.isModified), 
   switchMap(x => dataService.update(x))
)

这是我相信将有助于演示的stackblitz 。

在这里你可以看到我有一个组件,它允许更新从我的 observable 返回的项目的名称。我希望能够修改这些项目,然后将它们存储回 observable。这样,如果我想获得所有修改过的项目,我可以对那个 observable 应用一个过滤器来获得修改过的项目。此外,如果您更改 observable 将从服务器中拉出的日期,那么修改项目的列表将被清除。

DataService.itemNameChanged

标签: angularrxjs

解决方案


要解决这个问题,您可以使用扫描运算符来保存数组中新项目的值。

这里创建了一个 BehaviorSubject 以发出每个修改的新项目的值,它使用默认数组的第一个值进行初始化。

  private itemModified = new BehaviorSubject<Model>(data[0]);

每次更新 dateRefresh$ 的基本 observable 时,都应该重置这个值。

  readonly dateRefreshHttp$: Observable<Model[]> = combineLatest([
    this._date,
    this._refresh
  ]).pipe(
    tap(() => this.itemModified.next(data[0])),
    switchMap(([date, refresh]) =>

扫描操作符被添加到 switchMap 中,以便在发生变化时重新启动累加器。请注意添加的 debounce 运算符以允许在不失去焦点的情况下多次输入字符。

   switchMap(([date, refresh]) =>
      combineLatest([from([data]), this.itemModified]).pipe(
        scan(
          (acc: any[], [data, itemModified], index: number) => {
            return acc.map(item =>
              item.id == itemModified.id ? itemModified : item
            );
          },
          [...data]
        )
      )
    ),
    debounceTime(300)
  );

最后,通过 itemNameChanged 函数发出一个新值。

  itemNameChanged(newName: string, item: Model) {
    const newItem: Model = {
      id: item.id,
      name: newName,
      isModified: true
    };

    this.itemModified.next(newItem);
  }

活生生的例子,Stackblitz


推荐阅读