1π
β
This should do it:
computed: {
filteredPages() {
return this.pages.map(page => ({
...page,
children: page.children
// when children is truthy
? page.children.filter(
// filter out those not in `userPermissions`
child => this.userPermissions.includes(child.permissions)
// and those not in `activatedModules`
&& this.activatedModules.includes(child.moduleID)
)
: page.children
})).filter(
// only keep page if in `activatedModules` and...
page => (this.activatedModules.includes(page.moduleID)) &&
// if children is truthy and has length or...
(page.children?.length || (
// if children is falsy and page.permissions in userPermissions
!page.children && this.userPermissions.includes(page.permissions)
))
);
}
}
See it working:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
pages: [
{
text: 'Team',
moduleID: 'm1',
children: [
{ text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' }
],
}, {
text: 'Planner',
moduleID: 'm2',
children: [
{ text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
{ text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
],
}, {
text: 'HR',
moduleID: 'm3',
children: [
{ text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
{ text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
],
}, {
text: 'Admin',
moduleID: 'm4',
children: [
{ text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
{ text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
],
},
{ text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' }
],
activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50']
}),
computed: {
filteredPages() {
return this.pages.map(page => ({
...page,
children: page.children
? page.children.filter(
child => this.userPermissions.includes(child.permissions)
&& this.activatedModules.includes(child.moduleID)
)
: page.children
})).filter(
page => (this.activatedModules.includes(page.moduleID))
&& (page.children?.length || (
!page.children && this.userPermissions.includes(page.permissions)
))
);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<pre v-html="filteredPages" />
</div>
1π
in the code snippet below I used a filter first to filter by activatedModules
then used a forEach
to filter each object children
property by userPermissions
, I think you can implement this in your vue component or get an idea about how to tackle the problem (hope this helps):
const pages = [{
text: 'Team',
moduleID: 'm1',
children: [{
text: 'Dashboard',
route: 'team/dashboard',
permissions: 'p1382',
moduleID: 'm1-1'
}, ],
},
{
text: 'Planner',
moduleID: 'm2',
children: [{
text: 'Events',
route: '/planner/events',
permissions: 'p47289',
moduleID: 'm2-1'
},
{
text: 'Calendar',
route: '/planner/calendar',
permissions: 'p283',
moduleID: 'm2-2'
},
],
},
{
text: 'HR',
moduleID: 'm3',
children: [{
text: 'Staff',
route: '/hr/staff',
permissions: 'p34729',
moduleID: 'm3-1'
},
{
text: 'Config',
route: '/hr/config',
permissions: 'p382',
moduleID: 'm3-2'
},
],
},
{
text: 'Admin',
moduleID: 'm4',
children: [{
text: 'Users',
route: '/admin/users',
permissions: 'p3z4',
moduleID: 'm4-1'
},
{
text: 'Security',
route: '/admin/security',
permissions: 'p2u3',
moduleID: 'm4-2'
},
],
},
{
text: 'Support',
route: '/support',
permissions: 'p332j',
moduleID: 'm5'
},
];
const activatedModules = ['m1', 'm3', 'm4', 'm5'];
const userPermissions = ['m1-1', 'm3-1', 'm3-2', 'm4-2'];
// This is the source for my navigation drawer:
let filteredPages = null;
filteredPages = pages.filter(x => activatedModules.includes(x.moduleID));
filteredPages.forEach(x => {
if (x.children)
x.children = x.children.filter(y => userPermissions.includes(y.moduleID));
});
console.log(filteredPages);
1π
Some remarks:
- You should not be using
function
for callbacks, like you started doing forfilter
, as that will make you lose the rightthis
value. Use arrow functions. filter
cannot do the job on its own, as you need to also generate new objects which may have fewer children. So you should firstmap
to make those narrowed down objects, and thenfilter
.
Without using Vue, you can run the following snippet, which just hard-codes the call to filterArray
:
let app = {
computed: {
filterArray() {
this.filteredPages = this.pages.map(item => {
let children = (item.children || []).filter(child =>
this.activatedModules.includes(child.moduleID) &&
this.userPermissions.includes(child.permissions)
);
return (children.length || !item.children)
&& this.activatedModules.includes(item.moduleID)
&& {...item, children};
}).filter(Boolean);
}
},
data: () => ({
pages: [
{
text: 'Team', moduleID: 'm1',
children: [
{ text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' },
],
},
{
text: 'Planner', moduleID: 'm2',
children: [
{ text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
{ text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
],
},
{
text: 'HR', moduleID: 'm3',
children: [
{ text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
{ text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
],
},
{
text: 'Admin', moduleID: 'm4',
children: [
{ text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
{ text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
],
},
{ text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' },
],
activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50'],
filteredPages: []
}),
};
// Demo, simulate Vue's call to computed.filterArray
let data = app.data();
app.computed.filterArray.call(data);
// Verify output:
console.log(data.filteredPages);
Source:stackexchange.com