将 parent child 结构展平为解析为数组的 BehaviorSubject
Flatten a parent child structure to a BehaviorSubject that resolves to an array
我有一个 BehaviourSubject
解析为一个集合,其中的每个项目都有一个 属性 children
,它也是一个 BehaviourSubject
解析为一个项目集合。
现在我想订阅我的主题并将整个内容展平成一个数组,其中每个项目和每个 child.
都有一行
所以符合以下内容:
interface Parent = {
children: BehaviorSubject<Child[]>
}
现在我想从中创建另一个行为主题,解析为一个数组,其中每个 parent 都有一个项目,后跟 children.
开始于:
const collection: BehaviorSubject<Parent[]>;
想要结果:
const behaviourSubject: BehaviorSubject<(Parent|Child)[]>;
behaviourSubject.subscribe((result: (Parent|Child)[]) => {
...desired result...
});
所以假设集合中的第一个 Parent
有 3 children,第二个有 2 children 那么如果我订阅结果 behaviourSubject
输出应如下所示。
result: [Parent, Child, Child, Child, Parent, Child, Child];
我该如何实现。
我试图通过阅读 RxJS 的文档和检查示例来弄清楚如何做到这一点,但我想最近睡眠不足似乎让我的大脑像干海绵一样工作,我认为最好的方法是正确的现在是在 Whosebug 上寻求帮助。
注意:如果parent集合或children得到一个新值,结果也应该更新...
像下面这样的东西显示了工作,但我想知道你为什么使用 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'),
])),
]);
这里是最终的可观察对象,它在管道中进行了不同的操作,并添加了注释以解释它们在订阅结果时究竟做了什么:
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)
我有一个 BehaviourSubject
解析为一个集合,其中的每个项目都有一个 属性 children
,它也是一个 BehaviourSubject
解析为一个项目集合。
现在我想订阅我的主题并将整个内容展平成一个数组,其中每个项目和每个 child.
所以符合以下内容:
interface Parent = {
children: BehaviorSubject<Child[]>
}
现在我想从中创建另一个行为主题,解析为一个数组,其中每个 parent 都有一个项目,后跟 children.
开始于:
const collection: BehaviorSubject<Parent[]>;
想要结果:
const behaviourSubject: BehaviorSubject<(Parent|Child)[]>;
behaviourSubject.subscribe((result: (Parent|Child)[]) => {
...desired result...
});
所以假设集合中的第一个 Parent
有 3 children,第二个有 2 children 那么如果我订阅结果 behaviourSubject
输出应如下所示。
result: [Parent, Child, Child, Child, Parent, Child, Child];
我该如何实现。
我试图通过阅读 RxJS 的文档和检查示例来弄清楚如何做到这一点,但我想最近睡眠不足似乎让我的大脑像干海绵一样工作,我认为最好的方法是正确的现在是在 Whosebug 上寻求帮助。
注意:如果parent集合或children得到一个新值,结果也应该更新...
像下面这样的东西显示了工作,但我想知道你为什么使用 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'),
])),
]);
这里是最终的可观察对象,它在管道中进行了不同的操作,并添加了注释以解释它们在订阅结果时究竟做了什么:
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)