angular - 有角度的多个流,一个可观察的
问题描述
我有基于特定日期从服务器中提取的数据。因此,当日期更改时,我再次从服务器查询以获取新数据。我还可以从服务器手动触发刷新(对于我从中提取数据的情况,因此我需要重新提取)
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
解决方案
要解决这个问题,您可以使用扫描运算符来保存数组中新项目的值。
这里创建了一个 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