由于标题可能无法解释我正在做的事情,我将举一个小例子:
REST api返回一个对象列表。对于它们中的每一个,都应显示一个复选框,并将所选值用于进一步处理。但是,api可能被多次调用(刷新数据),因此我处理的是Observables,结果(即所选对象)也应该可以作为Observable使用。
I have created a simple Plunker to illustrate this:我在Component中收到一个带有对象数组的observable(这里只是简化的字符串):
var observable = Observable.of(["Hello", "World"]);
基于此,我创建类型为Item
的对象,同时存储对象和信息是否被检查(作为Observable / BehaviorSubject):
this.items$ = observable.map(arr => arr.map(s => new Item(s)))
//...
class Item {
public readonly isChecked$ : BehaviorSubject<boolean> = new BehaviorSubject(false);
constructor(public readonly value : string) { }
}
然后,我使用How to two-way bind my own RxJS Subject to an [(ngModel)]?的解决方案显示它们:
<li *ngFor="let item of items$ | async as items" >
<input id="cb-{{item.value}}" type="checkbox" [ngModel]="item.isChecked$ | async" (ngModelChange)="item.isChecked$.next($event)" />
<label for="cb-{{item.value}}">{{item.value}}</label>
</li>
但是,我现在遇到了包含所选值的Observable<string[]>
的实际问题。基本上,我有一个Observable<Item[]>
,我需要:
第三个是我无法实现的:例如,一旦我flatMap
数组,似乎就没有回复&#34;再次创建一个数组 - 我不想最终得到一个Observable<string>
(当选中一个新项目时通知我),但是每次选择的项目集合都会引发Observable<string[]>
变化。
我能想到的最好的是plunker中的代码(依赖于subscribe +手动将值插入第二个数组):
this.items$
.switchMap(items => items.map(item => item.isChecked$.map(isChecked => ({ checked: isChecked, value: item.value}))))
.mergeAll()
.subscribe(o => {
var selected = this._selectedItems.slice(0);
if (o.checked)
selected.push(o.value);
else {
var index = selected.indexOf(o.value);
selected.splice(index, 1);
}
this._selectedItems = selected;
this._selectedItems$.next(this._selectedItems);
});
在rxjs中是否有更优雅的功能允许我实现这一点(不需要第二个数组)?
答案 0 :(得分:0)
如果要将值推送到另一个observable,则应使用Subject
。 Subject
既是观察者又是观察者。
因此,您的过滤器可以使用next()
方法将值推送到新的observable中,类似这样的
mySubject.next(val)
您的代码的另一部分可以订阅此主题,并做出相应的反应
答案 1 :(得分:0)
考虑让BehaviorSubject
与您的商品列表保持同步,然后您可以将复选框事件映射到所有商品的状态。
const item_subject$ = new BehaviorSubject([]); // BehaviorSubject<Item[]>
items$.scan((acc, item) => acc.push(item), [])
.subscribe(item_subject$);
const checked_subject$ = new Subject(); // Subject<string[]>
items$.subscribe(item =>
item.isChecked$.subscribe(_ =>
checked_subject.next(
item_subject$.getValue()
.filter(inner_item => inner_item.isChecked$.getValue())
.map(inner_item => inner_item.value)
)
)
);
<强>定时:强>
checked_subject$
应该永远不会出现误报,这要归功于isChecked$
更新其值isChecked$
向其订阅者发送的事件。唯一的竞争部分可能是假设在第2行scan
之前发生的事情,将新项目推入item_subject
与项目更改状态。我想象的不是现实问题,因为用户必须在新项目呈现时立即点击。