I am trying to create a vue/vuetify (v2) application that has a login page (without toolbar/drawer) and other pages(with toolbar/drawer). That is why I started to use nested routes. But unfortunately I cannot figure out how to do it properly. And page is falling apart.
Here image 1. show what I want to achieve and image 2. shows what i get.
My routes.ts:
{
path: '/auth',
component: Authenticated,
meta: {requiresAuth: true},
children: [
{
path: 'home',
name: 'Home',
component: Home,
meta: {requiresAuth: true},
},
]
},
{
path: '/login',
name: 'login',
component: Login,
},
My App.vue
<template>
<v-app>
<v-main>
<router-view/>
</v-main>
<snackbar/>
</v-app>
</template>
And my Authenticated.vue
<template>
<div>
<v-app-bar dense dark class="primary">
...
</v-app-bar>
<v-navigation-drawer permanent clipped>
...
</v-navigation-drawer>
<router-view/>
</div>
</template>
I'm not sure I'm doing this the right way but I achieved this by checking if there was a user un session, so my App.vue looks like this :
<template>
<v-app>
<t-nav v-if="$store.getters.userInSession"></t-nav>
<v-main>
<router-view></router-view>
</v-main>
</v-app>
</template>
And then my custom t-nav component is like this:
<template>
<div>
<v-app-bar :color="grey" short app>
<v-app-bar-nav-icon #click="toggleMenu" class="white--text"></v-app-bar-nav-icon>
<v-spacer></v-spacer>
<v-toolbar-title class="white--text">{{ currentRouteName | uppercase }}</v-toolbar-title>
</v-app-bar>
<v-navigation-drawer
app
color="dark"
dark
v-model="showMenu"
mobile-breakpoint="500"
>
</v-navigation-drawer>
</div>
</template>
It's quite the same as your code, except that you're trying to put your nav inside the main with the router-view and not outside.
Related
I am currently getting to know the vue framework with vuetify, and I am running into a couple issues here ... I have laid out a simple layout for the main page, but for whatever reason, the buttons do not fill the full height, and the background color is using (by default) the hover color. this is what it looks like:
The Code:
<template>
<v-app>
<v-app-bar app> </v-app-bar>
<v-main>
<router-view />
</v-main>
<v-bottom-navigation app v-model="value">
<v-btn value="cards" to="/cards">
<span>Cards</span>
<v-icon>mdi-cards</v-icon>
</v-btn>
<v-btn value="decks" to="/decks">
<span>Decks</span>
<v-icon>mdi-mail</v-icon>
</v-btn>
</v-bottom-navigation>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
value: 'cards',
}),
}
</script>
it is quite odd that this is happening as the application will randomly fix itself every once in a while when deleting random lines of code, then when I try to change something on the navigation, it will then break again.
Below is the template of my App.vue.
It employs Vuetify's <v-main> and <v-app-bar> UI architecture.
Now I'm wondering how to achieve inter-component communication between the component that lives inside <v-main> and the component that lives inside <v-app-bar>.
<template>
<v-app>
<v-app-bar app color="primary" dark>
<ReadingSelector
:selectedReading="selectedReading"/>
</v-app-bar>
<v-main>
<router-view></router-view>
</v-main>
</v-app>
</template>
My routes contain a single component:
const routes = [
{ path: '/', component: Controller }
]
What is the most elegant and simple way to proceed architecturally?
Is Vuex the answer or is there a better way?
I created a navigation drawer using Vuetify but none of the menus can be clicked.
Here's the code
<v-navigation-drawer v-model="drawer" temporary app class="primary">
<v-list>
<v-list-item v-for="link in links" :key="link.text" link :to="link.path">
<v-list-item-action>
<v-icon class="white--text">{{link.icon}}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title class="white--text">{{link.text}}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<template v-slot:append>
<div class="pa-2">
<v-btn block>
Sign out
<v-icon right>mdi-exit-to-app</v-icon>
</v-btn>
</div>
</template>
</v-navigation-drawer>
data() {
return {
drawer: false,
links: [
{icon: 'mdi-view-dashboard', text: 'Dashboard', path: '/'},
{icon: 'mdi-application-edit', text: 'Settings', path: '/settings'}
]
}
}
I have checked the routes in index.js and there is nothing wrong there. Also, if I go to /settings page, the Setting menu will be highlighted (active) but still cannot be clicked. How to fix this?
Solved it! The Navbar component was nested in a v-app-bar and somehow it affected the navbar. So I only removed the v-app-bar and the navigation drawer works perfectly fine!
So I have a basic layout :
<template>
<q-layout view="lHh Lpr lFf">
<q-header elevated class="bg-secondary text-white">
<q-toolbar >
<slot name="toolbar"></slot>
</q-toolbar>
</q-header>
<q-page-container >
<router-view ></router-view>
</q-page-container>
</q-layout>
</template>
And a basic router:
const routes = [
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') }
]
}
]
and Index.vue:
<template>
<q-page>
<template v-slot:default> CONTENT SHOWS</template>
<template v-slot:toolbar> CONTENT DOESN'T SHOW</template>
</q-page>
</template>
What do I do wrong? How can I get the slot up the router?
Simple answer: there is no way to accomplish that using slots.
You are seeing CONTENT SHOW because q-page has the default slot, but there is no definition for the toolbar slot there. Remember, slots get passed to their direct parents, this is a Vue fundamental rule. Your practice moved me to the age of master pages.
Using Name Views is the proper solution -- should move your toolbars into separate components and define them in routes.
Another solution, check the current route and render a proper toolbar:
<template>
<q-layout view="lHh Lpr lFf">
<q-header elevated class="bg-secondary text-white">
<q-toolbar>
<template v-if="$route.name === 'Index'">
<div>Toolbar for Index Page </div>
</template>
<template v-else-if="$route.fullPath.startsWith('/nested')">
<div>Toolbar for Index2 Page </div>
</template>
<template v-else>
<div>Toolbar for Default Pages </div>
</template>
</q-toolbar>
</q-header>
<q-page-container>
<router-view></router-view>
</q-page-container>
</q-layout>
</template>
Of course, moving these v-if logics into a separate component is a better practice.
It's been a long time since the original post, but maybe it can help someone else. Use names in router-view.
<template>
<q-layout view="lHh Lpr lFf">
<q-header elevated class="bg-secondary text-white">
<q-toolbar >
<router-view name="toolbar"></router-view>
</q-toolbar>
</q-header>
<q-page-container >
<router-view></router-view>
</q-page-container>
</q-layout>
</template>
Then, the route setup can contains something like this
const routes = [
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
children: [{
path: '',
components : {
default: () => import('pages/Index.vue'),
toolbar: () => import('some another page or component.vue')
}
}]
}
]
I use vuetify https://vuetifyjs.com/en/
My parent component like this :
<template>
<v-container>
...
<v-col
v-for="(item, i) in items"
:key="i"
>
<v-card
>
<v-app-bar dark color="grey">
<v-toolbar-title>Weekly Schedule : {{item.name}}</v-toolbar-title>
<div class="flex-grow-1"></div>
<modal-datepicker :schedule="item" />
</v-app-bar>
</v-col>
...
</v-container>
</template>
<script>
import { mapState } from "vuex";
import modalDatepicker from "../views/modalDatepicker";
export default {
components: {modalDatepicker},
};
</script>
My child component like this :
<template>
<v-dialog
:ref="dialog"
v-model="modal"
:return-value.sync="date"
>
<template v-slot:activator="{ on }">
<v-btn color="success" dark v-on="on">Show datepicker</v-btn>
</template>
<v-row justify="center">
<v-date-picker v-model="date" scrollable>
<div class="flex-grow-1"></div>
<v-btn text color="primary" #click="modal = false">Cancel</v-btn>
<v-btn text color="primary">OK</v-btn>
</v-date-picker>
</v-row>
</v-dialog>
</template>
<script>
import { mapState } from "vuex";
import modalDatepicker from "../views/modalDatepicker";
export default {
components: {modalDatepicker},
props: ['schedule'],
data: () => ({
date: new Date().toISOString().substr(0, 10),
modal: false,
}),
mounted() {
console.log(this.schedule)
},
};
</script>
The code above works, but seems inefficient. because every time the loop, it call modal dialog. I want modal to only be called when user click show datepicker button
how do i do that?
Apologies as I am on my mobile. Have you considered having the modal in your parent component outside of the loop?
You could have a data variable to handle your modal e.g
modal: {
open: false,
schedule: null }
Essentially then when your button is clicked you could add a v-click with a function that controls this data which in turns handles the content in the modal.
Then on your date picker or modal have a function to handle the update/close to clear this data and handle whatever you need too outside.
Then you could combine this into one component.
I see you have vuex you could also use vuex to control your modal and it’s contents.