我有一个带有子对象的数组,需要递归地在每个对象中设置一个字段(隐藏)。每个值都在预订中设置。我想等到订阅中的递归更新数组中的每个项目之前。
将基于从另一个可观察对象派生的角色和权限来设置隐藏字段。在示例中,我添加了一个延迟来模拟。
这是我的第一遍。我敢肯定有一种更干净的方法来解决这个问题。
https://codesandbox.io/s/rxjs-playground-hp3wr
// Array structure. Note children.
const navigation = [
{
id: "applications",
title: "Applications",
children: [
{
id: "dashboard",
title: "Dashboard"
},
{
id: "clients",
title: "Clients"
},
{
id: "documents",
title: "Documents",
children: [
{
id: "dashboard",
title: "Dashboard"
},...
]
},
{
id: "reports",
title: "Reports"
},
{
id: "resources",
title: "Resources"
}
]
}
];
在代码沙箱示例中,查看控制台消息,我得到了正确的结果。但是,我想避免必须订阅setHidden和recursivelySetHidden。我也想避免使用Subject。
答案 0 :(得分:0)
这是我的方法:
const roleObservable = timer(1000).pipe(mapTo("**************"));
function populateWithField(o, field, fieldValue) {
if (Array.isArray(o)) {
return from(o).pipe(
concatMap(c => populateWithField(c, field, fieldValue)),
toArray()
);
}
if (o.children) {
return roleObservable.pipe(
tap(role => (fieldValue = role)),
concatMap(role => populateWithField(o.children, field, role)),
map(children => ({
...o,
[field]: fieldValue,
children
}))
);
}
return roleObservable.pipe(
map(role => ({
[field]: role,
...o
}))
);
}
of(navigation)
.pipe(concatMap(o => populateWithField(o, "hidden")))
.subscribe(console.log, e => console.error(e.message));
要注意的主要事情是频繁使用concatMap
。它是higher-order mapping operator,这意味着除其他外,它将自动从其内部可观察的对象中订阅/取消订阅。
concatMap
与其他运算符的不同之处在于,它会保留发射值的缓冲区,这意味着它将等待等待当前内部的可观察在订阅下一个之前完成。
在这种情况下,您必须处理很多Observables-of-Observables(higher-order observables
),这是为什么,您必须每次使用concatMap
遇到children
属性的时间。该属性中的任何子级都可以拥有自己的children
属性,因此您必须确保Observable包含仅 一阶 Observable。
您可以了解有关高阶和一阶可观察物here的更多信息。