类似下面的东西展示了工作,但我想知道你为什么使用 BehaviorSubject 来增加复杂性
import { first, switchMap, toArray, map } from 'rxjs/operators';
import { pipe, BehaviorSubject, from } from 'rxjs';
//...
const parent1={children:new BehaviorSubject([{name:'john'},{name:'may'},{name:'betty'}])}
const parent2={children:new BehaviorSubject([{name:'key'},{name:'tom'}])}
const collection=new BehaviorSubject([parent1,parent2]);
collection.pipe(
first(),
switchMap(parent=>from(parent)),
switchMap(p=>p.children.pipe(first(),map(c=>[p,...c]))),
toArray(),
map(arr=>arr.flat())
).subscribe(console.log)
如果您不介意使用 BehaviourSubject 中的 .value 属性,代码可以简化为以下
collection.value.map(p=>[p,...p.children.value]).flat()
编辑(由 OP):
我将为那些想知道此答案中不同步骤的人编辑此问题,我将其分解为几部分。
也可以在 this StackBlitz 中找到它来玩弄。
构建数据:
import { first, switchMap, toArray, map } from 'rxjs/operators';
import { pipe, BehaviorSubject, from } from 'rxjs';
class Child {
constructor(public name: string){
}
}
class Parent {
constructor(public children: BehaviorSubject<Child[]>){
}
}
const collection = new BehaviorSubject([
new Parent(new BehaviorSubject([
new Child('john'),
new Child('may'),
new Child('betty'),
])),
new Parent(new BehaviorSubject([
new Child('key'),
new Child('tom'),
])),
]);
这里是最终的 observable,它在管道中添加了 cmets 以解释它们在订阅结果时的确切作用:
collection.pipe(
//Emit the first value
first(),
// Complete previous inner observable, emit values
switchMap((parents: Parent[]) => {
// Emit array as a sequence of values
return from(parents)
}),
// complete previous inner observable, emit values
switchMap((parent: Parent) => {
return parent.children.pipe(
// Emit the first value
first(),
// Apply projection with each value from source
map(
(children: Child[]) => {
// return desired array for each parent
return [parent, ...children];
}
)
)
}),
//Collects all source emissions and emits them as an array when the source completes
toArray(),
//map(arr=>arr.flat())
map((array: (Parent|Child)[][] ) => {
// Flatten the array
return array.flat();
}),
).subscribe(console.log)