我需要过滤的对象的递归阵列。 每个对象代表一个webapp路由/ URL。此网址可被限制到了一定的作用。(许可= TRUE | FALSE)或没有,每一个URL可以有子URL ...递归
修改复杂的部分是,过滤需要一个异步函数调用(我在我的项目,该项目的具体需要)。 这就是为什么我尝试使用RXJS做到这一点,但是我可以使用标准数组函数+ async / await来实现它。
我也借此机会多学习一些rxjs,这就是为什么我想要一个面向rxjs回答(这与它涉及异步,这是一个很好的方法胡?)。谢谢
具有此数组:
[
{
id: 'level 1.1',
permission: true,
children: [
{
id: 'level 2.1',
permission: false,
children: [
{id: 'level 3.1'}
]
},
{
id: 'level 2.2',
permission: true,
children: [
{id: 'level 3.2'}
]
}
]
},
{
id: 'level 1.2'
},
{
id: 'level 1.3',
permission: false
}
]
我需要过滤它有像(仅保留条目,其中权限不存在或truthy输出:
[
{
id: 'level 1.1',
permission: true,
children: [
{
id: 'level 2.2',
permission: true,
children: [
{id: 'level 3.2'}
]
}
]
},
{
id: 'level 1.2'
}
]
我尝试的方法没有递归(注释的代码),因此成功过滤了第一级,但是我不知道如何添加递归:
// simplified ASYNC filter function
promiseMe(x) {
return Promise.resolve().then(() => {
return x.permission === undefined || x.permission === true
});
}
// recursive function
const recursive = arr => {
return from(arr).pipe(
mergeMap(entry => from(this.promiseMe(entry)).pipe(
tap(y => console.log(y)),
filter(Boolean),
mapTo(entry),
tap(console.log),
mergeMap(item => {
// here I'm lost
// I need to affect the result of my async recursive function to item.children :
/*return recursive(item.children).pipe(
tap(res => {
console.log('RES', item, res)
item.children = res;
})
);*/
return of(item);
})
)),
toArray()
)
};
// main call
recursive(arr).subscribe(x => console.log('finally', x, JSON.stringify(x)))
FIDDLE这里:https://stackblitz.com/edit/angular6-rxjs6-playground-idysbh?file=app/hello.component.ts
答案 0 :(得分:5)
我无法为什么你需要RxJS处理您的列表搞清楚。
我建议此实现:
const source = [
{
id: 'level 1.1',
permission: true,
children: [
{
id: 'level 2.1',
permission: false,
children: [
{id: 'level 3.1'}
]
},
{
id: 'level 2.2',
permission: true,
children: [
{id: 'level 3.2'}
]
}
]
},
{
id: 'level 1.2'
},
{
id: 'level 1.3',
permission: false
}
];
const isAllow = item => {
return item.permission === undefined || item.permission;
};
const filtering = (list) => {
const listing = [];
list.forEach(item => {
// If current one have permission.
if(isAllow(item)) {
// If he have child, let process it recursively.
if(item.children && item.children.length > 0) {
item.children = filtering(item.children);
}
// Add current on to whitelisted.
listing.push(item);
}
});
return listing;
};
console.log(filtering(source));
如果你想打开这个名单上rxjs流,你可以简单地使用map
of(source).pipe(map(source => filtering(source))).subscribe(console.log)
基于澄清,我以可观察的方式完成了与上面相同的代码。
目标是具有可观察工厂函数(此处为allowOnly$
)其中:
concatMap
带有ajax请求的项目。filter
项是不允许的。concatMap
又是新的combineLatest
,是当前项目和allowOnly$
的递归调用的组合,其中所有子项都作为参数。toArray
将我们当前的项目流转换回单个广播,所有项目合并在阵列上。Voilà
const dummyAjaxRequest = (item) => {
return of({
...item,
permission: (item.permission === undefined || item.permission)?true:false
});
}
const allowOnly$ = items => {
return from(items).pipe(concatMap(item => {
return from(
/**
* Perform your ajax request here to find what's is allow or not.
*/
dummyAjaxRequest(item)
).pipe(
/**
* Exclude what is not allowed;
*/
filter(item => item.permission),
concatMap(item => {
/**
* If we have child, perform recursive.
*/
if (item.children) {
/**
* combine child and parent.
*/
return combineLatest(
allowOnly$(item.children), // Recursive call.
of(item)
).pipe(map(i => {
return {
...i[1], // all property of current,
children : [...i[0]] // Create new array base on allowed childrens.
};
}))
}
else {
/**
* No child, return simple observable of current item.
*/
return of(item);
}
})
);
}), toArray()); // transform stream like --|-|-|-> to --[|,|,|]->
};
of(source).pipe(concatMap(items => {
return allowOnly$(items);
})).subscribe(console.log);
重要说明所有mergeMap
都切换到concatMap
来遵守原始列表顺序,而不是混合所有首先基于ajax请求的项目。 >