Dynamic Buttons in Navigation Bar using Vuetify

11,232

I did the same thing as you in a recent project and found altering the structure was the easier way to fix issues like this.

My structure was as follows:

app.vue: Only contains <router-view> no other components

router.js: Parent route is a layout component, all sub routes which contains my toolbars and other layout components and it's own <router-view> which receives child routes

ex:

{
  path: '/login',
  name: 'Login',
  component: load('login')
},
{
  path: '/',
  component: load('main-layout'),
  children: [
    {
      path: '',
      name: 'Home Page',
      component: load('homePage')
    },
    {
      path: '/settings',
      name: 'Settings',
      component: load('settings'),
    }
  ]
}

Now in your main-layout:

computed: {
  showHomeButton () {
    if (this.$route.path === '/') {
      return true
    }
    return false
    // Repeat for other routes, etc...
  },
}
Share:
11,232
Brayan
Author by

Brayan

Updated on July 23, 2022

Comments

  • Brayan
    Brayan almost 2 years

    I have a problem... My VueJS Application using Vuetify. I have a <v-toolbar>, and on the right, I want to place some buttons that change depending on the component shown in <router-view>, but i can't access to component properties from $route or $route for get objects and methods bind to model of my component.

    I would like to know if there is any way to assign a model to from my main component.

    I have tried with "named-routes" but I do not know what is the way that properties can be shared between components that are managed by an <router-view> and updated live.

    In resume:

    I have my application skeleton with a navigation bar, additionally in the dynamic content I have a <router-view>. Depending on the component that is displayed in <router-view>, I would like to see buttons in the navigation bar corresponding to that component, which interact and change the data or execute methods of the component.

    App.vue

    <template>
      <v-app>
    		<router-view></router-view>
      </v-app>
    </template>
    
    <script>
    	export default {
    		name: 'App',
    		data() {
    			return {
    				
    			};
    		}
    	};
    </script>

    index.js (router)

    import Vue from 'vue'
    import Router from 'vue-router'
    import AppLogin from '@/components/AppLogin'
    import Skeleton from '@/components/Skeleton'
    import ShoppingCart from '@/components/ShoppingCart'
    import ShoppingCartButtons from '@/components/ShoppingCartButtons'
    import ProductSelection from '@/components/ProductSelection'
    import ProductSelectionButtons from '@/components/ProductSelectionButtons'
    import ProductDetail from '@/components/ProductDetail'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path : '/login',
          name : 'AppLogin',
          component : AppLogin
        },
        {
          path : '/app',
          name : 'Skeleton',
          component : Skeleton,
          children : [{
              path : 'shopping-cart',
              components : {
                navigation : ShoppingCart,
                navButtons : ShoppingCartButtons
              }
            }, {
              path: 'product-selection',
              name : 'ProductSelection',
              components : {
                navigation : ProductSelection,
                navButtons : ProductSelectionButtons
              }
            },
            {
              path: 'product-detail',
              name : 'ProductDetail',
              components : {
                navigation : ProductDetail
              },
              props : true
            }
          ]
        }
      ]
    })

    Skeleton.vue

    <template>
        <v-container fluid>
            <v-navigation-drawer
                persistent
                :mini-variant="miniVariant"
                :clipped="true"
                v-model="drawer"
                enable-resize-watcher
                fixed
                app
                >
                
                <v-list>
    
                <v-list-tile
                    value="true"
                    v-for="(item, i) in items"
                    :key="i"
                    :to="item.path">
    
                    <v-list-tile-action>
                    <v-icon v-html="item.icon"></v-icon>
                    </v-list-tile-action>
                    
                    <v-list-tile-content>
                    <v-list-tile-title v-text="item.title"></v-list-tile-title>
                    </v-list-tile-content>
                </v-list-tile>
                </v-list>
            </v-navigation-drawer>
    
            <v-toolbar
                app
                :clipped-left="clipped"
            >
                <v-toolbar-side-icon @click.stop="drawer = !drawer">
                </v-toolbar-side-icon>
                
                <v-toolbar-title v-text="$route.meta.title"></v-toolbar-title>
                <v-spacer></v-spacer>
                <router-view name="navButtons"></router-view>
    
            </v-toolbar>
        
            <v-content>
                <router-view name="navigation"/>
            </v-content>
    
            <v-footer :fixed="true" app>
    			<p style="text-align : center; width: 100%">&copy; CONASTEC 2018</p>
    		</v-footer>
        </v-container>
    </template>
    
    <script>
    export default {
      data() {
    	return {
    	  clipped: true,
    	  drawer: false,
    	  fixed: false,
    	  items: [
    		{
    		  icon: "shopping_cart",
    		  title: "Carrito de Compras",
    		  path : "/app/shopping-cart"
    		},
    		{
    		  icon: "attach_money",
    		  title: "Facturas"
    		},
    		{
    		  icon: "account_balance_wallet",
    		  title: "Presupuestos"
    		},
    		{
    		  icon: "insert_chart",
    		  title: "Informes"
    		},
    		{
    		  icon: "local_offer",
    		  title: "Productos"
    		},
    		{
    		  icon: "person",
    		  title: "Clientes"
    		},
    		{
    		  icon: "layers",
    		  title: "Cuenta"
    		},
    		{
    		  icon: "comment",
    		  title: "Comentarios"
    		},
    		{
    		  icon: "settings",
    		  title: "Ajustes"
    		}
    	  ],
    	  buttons : [],
    	  miniVariant: false,
    	  right: true,
    	  rightDrawer: false
    	};
      },
      name: "Skeleton"
    };
    </script>

    EDITED

    My solution is create a new component Toolbar and add slots for buttons to right and left.

    <template>
        <div>
            <v-navigation-drawer persistent :mini-variant="false" :clipped="true" v-model="drawer" enable-resize-watcher fixed app>
                <v-list>
                    <v-list-tile value="true" v-for="(item, i) in items" :key="i" :replace="true" :to="item.path">
        
                        <v-list-tile-action>
                            <v-icon v-html="item.icon"></v-icon>
                        </v-list-tile-action>
        
                        <v-list-tile-content>
                            <v-list-tile-title v-text="item.title"></v-list-tile-title>
                        </v-list-tile-content>
                    </v-list-tile>
                </v-list>
            </v-navigation-drawer>
        
            <v-toolbar app :clipped-left="true" color="primary" :dark="true" flat>
        
                <v-toolbar-side-icon v-if="showDrawer" @click.stop="drawer = !drawer">
                </v-toolbar-side-icon>
    
                <v-toolbar-side-icon v-if="!!back" @click="back">
                    <v-icon>keyboard_backspace</v-icon>
                </v-toolbar-side-icon>
                
                <v-toolbar-title v-text="title" style="font-size: 1.4em"></v-toolbar-title>
                <v-spacer></v-spacer>
                <v-card-actions>
                    <slot name="right"></slot>
                </v-card-actions>
        
            </v-toolbar>
            <v-snackbar
                :timeout="5000"
                :top="true"
                :multi-line="true"
                :vertical="true"
                v-model="snackbar.show"
                >
                {{ snackbar.content }}
                <v-btn flat color="white" @click.native="snackbar.show = false">Cerrar</v-btn>
            </v-snackbar>
        </div>
    </template>
    
    <script>
        export default {
            name: 'app-toolbar',
            props: ['title','showDrawer', 'back'],
            data() {
                return {
                    drawer : false,
                    items: [{
                        icon: "shopping_cart",
                        title: "Carrito de Compras",
                        path: "/carrito-compras"
                    }, {
                        icon: "attach_money",
                        title: "Facturas",
                        path: "/documentos-tributarios"
                    }, {
                        icon: "account_balance_wallet",
                        title: "Presupuestos"
                    }, {
                        icon: "insert_chart",
                        title: "Informes"
                    }, {
                        icon: "local_offer",
                        title: "Productos"
                    }, {
                        icon: "person",
                        title: "Clientes"
                    }, {
                        icon: "layers",
                        title: "Cuenta"
                    }, {
                        icon: "comment",
                        title: "Comentarios"
                    }, {
                        icon: "settings",
                        title: "Ajustes"
                    }]
                };
            },
            computed : {
                snackbar() {
                    return this.$store.getters.snackbar;
                }
            }
        }
    </script>

    and use is:

     <app-toolbar title="Carrito de Compras" :showDrawer="true">
        <template slot="right">
            <v-toolbar-side-icon @click="confirm">
                <v-icon>monetization_on</v-icon>
            </v-toolbar-side-icon>
    
        </template>
    </app-toolbar>

  • altShiftDev
    altShiftDev about 6 years
    @Brayan you're going to have to be more specific, I'm not sure what you're asking. Usually you send data down to other components with props and up with emit.