Angular RXJS 6:数组的递归筛选。。使用异步筛选器
我需要过滤对象的递归数组。 每个对象表示一个webapp路由/url。此url可以限制为某个角色(权限=true | false),也可以不限制,并且每个url都可以有子url。。。递归地 编辑:复杂的部分是过滤需要一个异步函数调用(我在我的项目中有这个特定的需求)。 这就是为什么我试着用RXJS实现它,但我可以用标准数组函数+async/await实现它 我还借此机会学习了更多的rxjs,这就是为什么我想要一个面向rxjs的答案(这是一个处理异步的好方法?)。谢谢 具有此阵列:Angular RXJS 6:数组的递归筛选。。使用异步筛选器,angular,asynchronous,filter,rxjs,Angular,Asynchronous,Filter,Rxjs,我需要过滤对象的递归数组。 每个对象表示一个webapp路由/url。此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
}
]
我需要对其进行过滤,使其具有如下输出(仅保留没有权限或真实的条目:
[
{
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)))
在这里摆弄:我不明白为什么需要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)
编辑一个:
基于澄清,我已经以可观察的方式完成了上述代码
目标是具有可观察的工厂功能(这里是allownly$
),它:
- 创建当前数组的每个项都将在其中广播的流
此项包含ajax请求concatMap
筛选不允许的项
再次新增concatMap
,它是当前项和combinelatetest
递归调用的组合,所有子项都作为参数allowOnly$
将当前项目流转换回单个广播,所有项目合并到阵列上toArray
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请求答案的项目
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)
编辑一个:
基于澄清,我已经以可观察的方式完成了上述代码
目标是具有可观察的工厂功能(这里是allownly$
),它:
- 创建当前数组的每个项都将在其中广播的流
此项包含ajax请求concatMap
筛选不允许的项
再次新增concatMap
,它是当前项和combinelatetest
递归调用的组合,所有子项都作为参数allowOnly$
将当前项目流转换回单个广播,所有项目合并到阵列上toArray
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请求答案的项目
权限
字段,并且您必须实现ajax请求询问这个标志,然后用这些新信息过滤你的原始列表。另一个问题:在进行任何处理之前,是否可以将列表展开?你所描述的是正确的。不可能展开,在我看来,在rxjs中构建一个组=>子菜单并不是那么自然的。有一个操作符叫做expand
用于满足您的需要。我不久前写了一个类似问题的答案,请检查:这也是不可能的,但我强烈建议您避免多次请求授权。对我来说,您应该解析您的对象并搜索每个需要检查的项,然后执行单个请求,再次解析您的对象并设置授权标志。嗨,Cétia,我仍然不知道你到目前为止试图实现什么。你能描述一下你的功能流程吗?听起来你有没有权限
字段的嵌套对象,你必须实现ajax请求来请求这个标志,然后用这个新信息过滤你的原始列表。另一个任务ion:在进行任何处理之前,是否可以将列表展平?您所描述的是正确的。不可能展平,在我看来,在rxjs中构建一个组=>子菜单Cursion并不是那么自然。有一个名为expand
的操作符用于满足您的需要。有一段时间,我为类似的问题写了一个答案ago,check out:这也是不可能的,但我强烈建议您避免多次请求授权。对于我来说,您应该解析您的对象并搜索每个需要检查的项目,然后执行单个请求,再次解析您的对象并设置授权标志。