Devildude4427
Devildude4427

Reputation: 1075

Vuetify Navigation Drawer with Sub-Menus

Like the title says, I'm trying to have a navigation drawer that has expandable sub-menus for certain options. Like a "User Profile" main menu option might have a the sub-menus "Update Contact Details" and "Review Registration".

I've tried this a handful of ways, basically coming down to the same two issues. Because each menu options is a list-tile, either the sub-menu gets stacked on the right of it (as in, the entire sub-menu is in the same tile), or the entire list of menu options has these drop down icons, when only a single menu option actually has a sub-menu. Additionally, my second code snippet below also stops you from navigating to any of the main menu links, which is not what is wanted.

Example 1, where the sub-menu is stuck in the same tile as the main menu option.

<div v-for="(link, i) in links" :key="i">
    <v-list-tile v-if="!link.subLinks" :to="link.to" :active-class="color" avatar class="v-list-item">
        <v-list-tile-action>
            <v-icon>{{ link.icon }}</v-icon>
        </v-list-tile-action>
        <v-list-tile-title v-text="link.text"/>
    </v-list-tile>

    <div v-else>
        <v-list-tile avatar class="v-list-item">
            <v-list-tile-action>
                <v-icon>{{ link.icon }}</v-icon>
            </v-list-tile-action>
            <v-list-tile-title v-text="link.text"/>
            <v-list-group>
                <v-list-tile sub-group v-for="(subLink, j) in link.subLinks" :key="j" :to="subLink.to" :active-class="color" avatar class="v-list-item">
                    <v-list-tile-title v-text="subLink.text"/>
                </v-list-tile>
            </v-list-group>
         </v-list-tile>
     </div>
</div>

Example 2, where each menu option has a drop down arrow, even ones that don't have any sub-menus.

<v-list-group v-for="(link, i) in links" :key="i" :prepend-icon="link.icon" :to="link.to" :active-class="color" avatar class="v-list-item">
    <template v-slot:activator>
        <v-list-tile>
            <v-list-tile-title>{{ link.text }}</v-list-tile-title>
        </v-list-tile>
    </template>

    <v-list-tile v-for="(subLink, j) in link.subLinks" :key="j" :to="subLink.to" :active-class="color">
        <v-list-tile-content>
            <v-list-tile-title>{{ subLink.text }}</v-list-tile-title>
        </v-list-tile-content>
    </v-list-tile>
</v-list-group>

This is a sample of the data I'm using

links: [
    {
        to: '/',
        icon: 'mdi-view-dashboard',
        text: 'Dashboard',
    },
    {
        icon: 'mdi-account',
        text: 'User Profile',
        subLinks: [
            {
                to: '/update-contact',
                text: 'Update Contact Details',
            },
            {
                to: '/review-registration',
                text: 'Review Registration',
            },
        ],
    },
],

What I'd like to be able to do is have a main menu, with the option of adding sub-menus as I see fit. Unfortunately, I can't seem to figure out how to mix and match the list-group and list-tile to get what I want done. I'm super grateful for any help provided. Thanks.

Upvotes: 14

Views: 26608

Answers (6)

Vusal Orujov
Vusal Orujov

Reputation: 33

You can use component tag <component></component> as parent

Upvotes: -1

Mohaimen Khalid
Mohaimen Khalid

Reputation: 135

enter image description here

This is three level category list item with navigation-drawer. This is actually find vuetify list section. then i modified this with three level item. You can extend and also optimized code. Just for example I write raw code.

<v-navigation-drawer
  v-model="drawer"
  :clipped="clipped"
  fixed
  app
>
  <v-list nav dense>
    <v-list-item
      to="/"
    >
      <v-list-item-icon>
        <v-icon>mdi-home</v-icon>
      </v-list-item-icon>

      <v-list-item-title>Home</v-list-item-title>
    </v-list-item>
  <!--Main category list-->
    <v-list-group
      v-for="item in items"
      :value="true"
      prepend-icon="mdi-food-apple"
      no-action
    >
    <template v-slot:activator>
      <v-list-item-title>{{item.name}}</v-list-item-title>
    </template>
       <!--Sub category item-->
        <!--if 2nd lvl child available-->
        <v-list-group
          v-if="subItem.children.length > 0"
          v-for="subItem in item.children"
          :value="true"
          sub-group
        >
        <template v-slot:activator>
          <v-list-item-content>
            <v-list-item-title>{{subItem.name}}</v-list-item-title>
          </v-list-item-content>
        </template>
            <!--subsubitem category list-->
            <v-list-item v-for="subSubItem in subItem.children" 
              :to="'/category/'+subSubItem.slug">
              <v-list-item-icon>
                <v-icon></v-icon>
              </v-list-item-icon>
              <v-list-item-title>{{subSubItem.name}}</v-list-item-title>
            </v-list-item>
        </v-list-group>
      <!--if not 2nd lvl child available-->
        <v-list-item :to="'/category/'+subItem.slug"  v-for="subItem in 
           item.children">
          <v-list-item-icon>
            <v-icon></v-icon>
          </v-list-item-icon>
          <v-list-item-title>{{subItem.name}}</v-list-item-title>
        </v-list-item>
    </v-list-group>
  </v-list>
</v-navigation-drawer>

DATA:

  [
  {
    "id": 1,
    "name": "Food",
    "slug": "food",
    "children": [
      {
        "id": 2,
        "name": "Fruits & Vegetables",
        "slug": "fruits-vegetables",
        "children": [
          {
            "id": 3,
            "name": "Fresh Fruits",
            "slug": "fresh-fruit",
            "children": []
          },
          {
            "id": 4,
            "name": "Fresh Vegetables\r\n",
            "slug": "fresh-vegetable",
            "children": []
          }
        ]
      },
      {
        "id": 5,
        "name": "Breakfast",
        "slug": "breakfast",
        "children": [
          {
            "id": 6,
            "name": "Local Breakfast",
            "slug": "local-breakfast",
            "children": []
          }
        ]
      }
    ]
  },
    {
      "id": 7,
      "name": "Home & Cleaning",
      "slug": "home-cleaning",
      "children": [
        {
          "id": 8,
          "name": "Air Fresheners",
          "slug": "air-freshners",
          "children": []
        },
        {
          "id": 9,
          "name": "Cleaning Supplies",
          "slug": "cleaning-supplies",
        }
      ]
    }
  ]

Upvotes: 1

Young Altair
Young Altair

Reputation: 1

I just found a way to set the submenu active-class. Hope it can help others. thanks to VueJS-Linusborg.

<template>
......
<v-list-group
  v-else
  :key="link.text"
  no-action
  :prepend-icon="link.icon"
  :value="subIsActive('/parentroute')"
>
<template v-slot:activator>
  <v-list-item-title>{{ link.text}}</v-list-item-title>
</template>
    
<v-list-item
  v-for="sublink in link.subLinks"
  :to="sublink.to"
  :key="sublink.text"
  :active-class="`success white--text`"
>
 <v-list-item-icon>
   <v-icon>{{ sublink.icon }}</v-icon>
 </v-list-item-icon>
 <-list-item-title>{{ sublink.text}}</v-list-item-title>
 </v-list-item>
</v-list-group>
...
</template>
<script>
...
methods:{
  subIsActive(input) {
    const paths = Array.isArray(input) ? input : [input];
    return paths.some((path) => {
    return this.$route.path.indexOf(path) === 0; // current path starts with this path 
    string
  });
},
....
}</script>

Upvotes: 0

SelfhostedPro
SelfhostedPro

Reputation: 159

I don't have enough reputation to add a comment but this will give you a bit of a better layout and function correctly (in the one posted above links didn't work for some reason and the naming was a bit off)

<template>
    <v-navigation-drawer
      app
      clipped
      permanent
      mini-variant
      expand-on-hover>
      <!-- -->

      <v-list nav dense>
       <div v-for="(link, i) in links" :key="i">

        <v-list-item
            v-if="!link.subLinks"
            :to="link.to"
            :active-class="color"
            avatar
            class="v-list-item"
        >
            <v-list-item-icon>
                <v-icon>{{ link.icon }}</v-icon>
            </v-list-item-icon>

            <v-list-item-title v-text="link.text" />
        </v-list-item>

        <v-list-group
            v-else
            :key="link.text"
            no-action
            :prepend-icon="link.icon"
            :value="false"
        >
            <template v-slot:activator>
              <v-list-item-title>{{ link.text }}</v-list-item-title>
             </template>

            <v-list-item
                v-for="sublink in link.subLinks"
                :to="sublink.to"
                :key="sublink.text"
            >
                <v-list-item-icon>
                  <v-icon>{{ sublink.icon }}</v-icon>
                </v-list-item-icon>
                <v-list-item-title>{{ sublink.text }}</v-list-item-title>

            </v-list-item>

        </v-list-group>

    </div>

      </v-list>

    </v-navigation-drawer>
</template>

<script>
export default {
  data: () => ({
links: [
    {
        to     : '/dashboard',
        icon   : 'mdi-view-dashboard',
        text   : 'Dashboard',
    },
    {
        icon     : 'mdi-folder',
        text     : 'Templates',
        subLinks : [
            {
                text : 'View Templates',
                to    : '/templates',
                icon  : 'mdi-view-list'
            },
            {
                text : 'New Template',
                to    : '/templates/new',
                icon  : 'mdi-plus'
            },
        ]
    },
    {
        icon     : 'mdi-application',
        text     : 'Applications',
        subLinks : [
            {
                text : 'View Applications',
                to    : '/apps',
                icon  : 'mdi-view-list'
            },
            {
                text : 'New Application',
                to    : '/apps',
                icon  : 'mdi-plus'
            },
        ]
    },
]
  })
}
</script>

<style scoped>
.v-application--is-ltr .v-list--dense.v-list--nav .v-list-group--no-action > .v-list-group__items > .v-list-item {
  padding: 0 8px;
}
</style>

Upvotes: 13

Ashadi Sedana Pratama
Ashadi Sedana Pratama

Reputation: 867

Hope this can help. Basically, the menu on the navigation drawer component (v-navigation-drawer) using the list component (v-list).

From the documentation, you can find a way to add submenu on list component on the part of nested list

Cheers,

Upvotes: 3

moonbas3
moonbas3

Reputation: 345

I was looking to do the same thing, here's how I solved it.

Data:

links: [
    {
        to     : '/dashboard',
        icon   : 'mdi-view-dashboard',
        text   : 'Dashboard',
    },
    {
        icon     : 'mdi-tennis',
        text     : 'Players',
        subLinks : [
            {
                text : 'Players list',
                to    : '/players',
            },
            {
                text : 'Import WTA Players',
                to    : '/players/import',
            },
        ]
    },
    {
        to     : '/tournaments',
        icon   : 'mdi-trophy',
        text   : 'Tournaments',
    },
]

Template:

<v-list>
    <div v-for="(link, i) in links">

        <v-list-tile
            v-if="!link.subLinks"
            :key="i"
            :to="link.to"
            :active-class="color"
            avatar
            class="v-list-item"
        >
            <v-list-tile-action>
                <v-icon>{{ link.icon }}</v-icon>
            </v-list-tile-action>

            <v-list-tile-title v-text="link.text" />
        </v-list-tile>

        <v-list-group
            v-else
            :key="link.text"
            no-action
        >
            <template v-slot:activator>
               <v-list-tile>
                 <v-list-tile-content>
                   <v-list-tile-title>{{ link.text }}</v-list-tile-title>
                 </v-list-tile-content>
               </v-list-tile>
             </template>

            <v-list-tile
                v-for="sublink in link.subLinks"
                :to="sublink.to"
                :key="sublink.text"
            >
                <v-list-tile-title v-text="sublink.text" />
            </v-list-tile>

        </v-list-group>

    </div>
</v-list>

I'm sorry but I don't have time to make a pen. Hope this helps !

Upvotes: 14

Related Questions