I want create a component that it can to scale with a nested object structure using the QExpansionItem from Quasar Framework.
I made a recursive component to try achieve this but doesn't shows like i hope. The items are repeated in a wrong way and I don't know why.
I am using Quasar V1.0.5, the component that i used QexpansionItem
Here the menu object
[
{
name: '1',
icon: 'settings',
permission: 'configuration',
description: '1',
url: '',
children: [
{
name: '1.1',
permission: 'configuration',
url: '/insuranceTypes',
icon: 'add',
description: '1.1'
},
{
name: '1.2',
permission: 'configuration',
url: '/insuranceTypes2',
icon: 'phone',
description: '1.2'
}
]
}, {
name: '2',
icon: 'person',
permission: 'configuration',
url: 'contacts',
description: '2'
}
]
MenuComponent.vue where i call side-tree-menu component
<q-list
bordered
class="rounded-borders q-pt-md"
>
<side-tree-menu :menu="menu"></side-tree-menu>
</q-list>
SideTreeMenuComponent.vue
<template>
<div>
<q-expansion-item
expand-separator
:icon="item.icon"
:label="item.name"
:caption="item.description"
header-class="text-primary"
:key="item.name"
:to="item.url"
v-for="(item) in menu"
>
<template>
<side
v-for="(subitem) in item.children"
:key="subitem.name"
:menu="item.children"
>
</side>
</template>
</q-expansion-item>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'side',
props: ['menu', 'children'],
data () {
return {
isOpen: false,
algo: 0
}
},
mounted () {
console.log('menu', this.menu)
},
computed: {
...mapGetters('generals', ['can'])
}
}
</script>
The elements 1.1 and 1.2 are repeated and I don't know fix it
I got stuck at the same problem and did not find any solution online. I managed to get it working with the below approach. This could be helpful for someone in the future :)
I am adding here the 2 most important code files that will get this working. Rest of my setup is nothing more than what is created by the quasar create [project-name] CLI command.
When you create the project with the above command, you get the MainLayout.vue and EssentialLink.vue file. I have modified those to achieve the required result.
**My MainLayout.vue file - the template **
EssentialLink below is the component that renders the menu recursively using q-expansion-item inside the drawer on the main layout page.
<template>
<q-layout view="hHh Lpr lFf">
<q-header elevated>
<q-toolbar>
<q-btn flat dense round icon="menu" aria-label="Menu"
@click="leftDrawerOpen = !leftDrawerOpen" />
<q-toolbar-title>
{{appTitle}}
</q-toolbar-title>
<div>Release {{ appVersion }}</div>
</q-toolbar>
</q-header>
<q-drawer
v-model="leftDrawerOpen" show-if-above bordered
content-class="bg-grey-1">
<q-list>
<q-item-label
header
class="text-grey-8">
Essential Links
</q-item-label>
<EssentialLink
v-for="link in essentialLinks"
:key="link.title"
v-bind="link">
</EssentialLink>
</q-list>
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
script section of MainLayout.vue file. Key properties to note - children and level.
<script>
import EssentialLink from 'components/EssentialLink.vue'
export default {
name: 'MainLayout',
components: {
EssentialLink
},
data () {
return {
appTitle: 'Project Name',appVersion: 'v0.1',leftDrawerOpen: false,
essentialLinks: [
{
title: 'Search', caption: 'quasar.dev', icon: 'school',
link: 'https://quasar.dev',
level: 0,
children: [{
title: 'Documents', caption: 'quasar.dev',icon: 'school',
link: 'https://quasar.dev',
level: 1,
children: [{
title: 'Search (level 3)',
caption: 'quasar.dev',
icon: 'school',
link: 'https://quasar.dev',
level: 2,
children: []
}]
}]
},
{
title: 'Github',caption: 'github.com/quasarframework',
icon: 'code',link: 'https://github.com/quasarframework',
level: 0,
children: [{
title: 'Github Level 2',caption: 'quasar.dev',icon: 'school',
link: 'https://quasar.dev',level: 1,
children: []
}]
},
{
title: 'Forum',caption: 'forum.quasar.dev',
icon: 'record_voice_over',link: 'https://forum.quasar.dev',
level: 0,
children: [{
title: 'Forum Level 2',caption: 'quasar.dev',icon: 'school',
link: 'https://quasar.dev',
level: 1,
children: []
}]
}
]
}
}
}
</script>
Finally the EssentialLink.vue component
The code below recursively calls itself when it encounters more than 1 item in its children property. The level property is used to indent the menus as you drill down.
<template>
<div>
<div v-if="children.length == 0">
<q-item clickable v-ripple :inset-level="level">
<q-item-section>{{title}}</q-item-section>
</q-item>
</div>
<div v-else>
<div v-if="children.length > 0">
<!-- {{children}} -->
<q-expansion-item
expand-separator
icon="mail"
:label="title"
:caption="caption"
:header-inset-level="level"
default-closed>
<EssentialLink
v-for="child in children"
:key="child"
v-bind="child">
</EssentialLink>
</q-expansion-item>
</div>
<div v-else>
<q-item clickable v-ripple :inset-level="level">
<q-item-section>{{title}}</q-item-section>
</q-item>
</div>
</div>
</div>
</template>
*script section of the EssentialLink.vue component
<script>
export default {
name: 'EssentialLink',
props: {
title: {
type: String,
required: true
},
caption: {
type: String,
default: ''
},
link: {
type: String,
default: '#'
},
icon: {
type: String,
default: ''
},
level: {
type: String,
default: ''
},
children: []
}
}
</script>