In my Vue.js application I use a navigation drawer to display the different pages a user has access to. Pages are also only visible if the administrator has activated the related module. Therefore the unique moduleID
is set for each page and children. The list is populated by filteredPages[]
. This array is the result of displaying only the pages a user has access to. All available pages are stored in my original data source pages[]
.
To sum this up: A page is only shown if both of these conditions are true:
activatedModules[]
contains themoduleID
of a page and the children.userPermissions[]
contains thepermissions
value of a children (or page if there is no children).
My code:
export default { 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'], // This is the source for my navigation drawer: filteredPages: [] }), computed: { filterArray() { // I tried to use filter() but how can I solve the rest? this.filteredPages = this.pages.filter(function(item) { for (var this.activatedModules in filter) { if /* I would assume that I have to write the condition here */ return false; } return true; }) } } }
For the code above this should be the output:
filteredPages: [ { text: 'Team', moduleID: 'm1', children: [ { text: 'Dashboard', route:'team/dashboard', permissions: 'p', moduleID: 'm1-1' }, ], }, // Notice that 'm2' is missing here because it is not in activatedModules[] { 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: [ // 'm4-1' is in activatedModules[] but the user doesn't have the permission 'p401' to view this { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' }, ], }, { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' }, ]
The permissions of a user are stored in Firebase Cloud Firestore like this:
Can you help with the filtering of the array?
Advertisement
Answer
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>