Vue.js - How to add multiple layout in vuejs? - javascript

I'm creating a vuejs app, in which I want to have two different layouts like one for user interface and other for the admin interface.
In the user interface, I have a button named "Admin Panel" on click to this button want to go the admin side and render the new layout. So far I have done this as follows:
I have created a container folder in my src to keep the layout files
UserPanel.vue
AdminPanel.vue
And also a router folder to keep the route files
user.js
admin.js
index.js
###UserPanel.js###
<template>
<v-app>
<h4>User Layout</h4>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
}
</script>
###AdminPanel.js###
<template>
<v-app>
<h4>Admin Layout</h4>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
}
</script>
###user.js###
import UserPanel from 'Container/UserPanel';
const HomeV1 = () => import('Views/HomeV1');
const HomeV2 = () => import('Views/HomeV2');
const HomeV3 = () => import('Views/HomeV3');
export default{
path: '/',
component: UserPanel,
redirect:'/home',
children:[
{
path: '/',
component: HomeV1 ,
meta: {
header: 1
}
},
{
path: '/home',
component: HomeV1 ,
meta: {
header: 1
}
},
{
path: '/home-two',
component: HomeV2 ,
meta: {
header: 2
}
},
{
path: '/home-three',
component: HomeV3 ,
meta: {
header: 3
}
}
]
}
###admin.js###
import Admin from 'Container/Adminpanel.vue';
const Reports = () => import('Views/AdminPanel/Reports.vue');
const Invoice = () => import('Views/AdminPanel/Invoices.vue');
const AdminAccount = () => import('Views/AdminPanel/Account.vue');
export default {
path: '/admin-panel',
component: Admin,
redirect:'/admin-panel/reports',
children:[
{
path: '/admin-panel/reports',
component: Reports,
name:'Reports'
},
{
path: '/admin-panel/invoices',
component: Invoice,
name:'Invoice'
},
{
path: '/admin-panel/products',
component: AdminProducts,
name:'AdminProducts'
}
]
}
###index.js###
import Vue from 'vue'
import Router from 'vue-router'
import userRoutes from './user';
import adminRoutes from './admin';
Vue.use(Router);
export default new Router({
mode: 'history',
routes: [
userRoutes,
adminRoutes
]
})
Now only my user routing is working. To show the pages of admin I have to put its route in user.js and after that, it renders the user's layout not admin's layout.
Thank You.

Put attribute meta in the route like this:
const routes = [
{
path: '/admin',
name: 'admin',
meta: { layout: 'LayoutAdmin' },
component: Dashboard,
},
and in App.vue you can render depends of this condition this.$route.meta.layout here an example:
<template>
<div id="app">
<notifications width="400px" />
<LayoutAdmin v-if="this.$route.meta.layout">
<router-view class="content" />
</LayoutAdmin>
<LayoutDefault v-else :links="links" :headerButtons="headerButtons">
<router-view class="content" />
</LayoutDefault>
</div>
</template>

I have played around with this before and the way I did it was to have alternative layouts that switch depending on a route meta field...
So when you define a route, you can add a meta field:
path: '/admin-panel/reports',
component: Reports,
name:'Reports',
meta: { template: 'admin' }
Then you need to check routes as they change. The easiest way to do this is in a global navigation guard (like the example has on their page). If it detects it's an admin page, it changes a Vuex property which will then switch which template you're using.
I will say that in the end I stopped using this method and wrapped all of my pages with wrapper components (admin/user/etc) so I could control everything from Vue itself. This was mainly due to Vue Router's limitations around waiting for a user to be authenticated though so that may not be an issue for you.

Related

Quasar Router routes not found

I'm using for the first time quasar router, I already know how to use Vue router and this one should be almost the same, and it quite is but the problem is it doesn't work, I have created a Login Page and tried to insert the route in routes.ts file but now i can't access the main page neither the login one, and when I look in the console I get this error: "Failed to fetch dynamically imported module: http://localhost:9000/src/layouts/MainLayout.vue".
Here's the code:
Routes.ts
import { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
// Main Page
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/QuestionsPage.vue') },
],
},
{
path: '/login',
component: () => import('pages/LoginPage.vue'),
},
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
export default routes;
In case you need the login page and the main one:
<script setup lang="ts"></script>
<template>
<q-page padding>
<h1>Login</h1>
</q-page>
</template>
<script setup>
console.log('test');
</script>
<template>
<q-page padding>
<h1>Main Page</h1>
</q-page>
</template>
File structure:

Why is my Vue navbar changing the route but not updating the router-view?

I'm using Vue to make a single-page application and I have a navbar and have set up Vue-Router. For some reason, every time after the first time I use the navbar, the route changes but the router-view does not. Here's the code from NavBar.vue:
<template>
<div id="app">
<v-toolbar id="navbar" app color="#330066" dark>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title id="appname">{{ appname }}</v-toolbar-title>
<v-spacer></v-spacer>
<span :key="item.link" v-for="item in items" class="nav-elt">
<router-link active-class="nav-elt-active" tag="span" :to="item.link">
{{ item.title }}
</router-link>
</span>
</v-toolbar>
</div>
</template>
<script>
export default {
name: "NavBar",
props: {
appname: String,
},
data() {
return {
items: [
{ title: "Home", link: "/" },
{ title: "Search", link: "/search" },
],
};
},
};
</script>
And here's from App.vue:
<template>
<v-app>
<v-main>
<NavBar appname="Newsfacts" />
<router-view />
</v-main>
</v-app>
</template>
<script>
import NavBar from "./components/NavBar";
export default {
name: "App",
components: {
NavBar,
},
data() {
return {};
},
};
</script>
Here's from router/index.js:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import Search from '../views/Search.vue';
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/search",
name: "Search",
component: Search
}
]
});
If you need anything else, the full code is on my github, and a demo is at a netlify site
The link attribute inside the array of items should contain a '/' at the beginning of every route.
So, it should look like this:
data() {
return {
items: [
{ title: "Home", link: "/home" },
{ title: "Search", link: "/search" },
],
};
},
Also, it is probable that the component is not being rendered because you are using <v-btn/> for routing, instead of <router-link/>.
I recommend you use <router-link/> instead of <v-btn/> for navigation in order to support all the features provided by Vue Router like history mode, base, etc.
In case you necessarily need the v-btn, I think you can wrap the <router-link/> inside the button or viceversa.
For more information about Vue Router and <router-link/>, check out this link:
https://router.vuejs.org/api/#router-link
where is your vue router component definitions?
e.g
const FooHome= { template: '<div>Home</div>' }
const Search= { template: '<div>Search</div>' }
const routes = [
{ path: '/', component: Home},
{ path: '/search', component: Search}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
Turns out I was returning an empty dictionary in a few data() functions, and that caused the app to break. Thanks to #inked6233 on the Vue Land discord for helping me find that!

How to include a component in all vue-routes?

In a SPA, I have made a header component which changes slightly on each page.
export default {
name: 'header',
//add some stuff based on user data
data: function (router) {
return {
//some data
}
},
}
And here are my routes:
export default [
{path:'/', component: showJokesAll },
{path:'/hot', component: showJokesHotAll },
{path:'/add', component: addJoke } ,
{path: '/login', component: webLogin},
{path: '/profile', component: webProfile},
{path: '/auth', component: webProfile},
]
I'm wondering what is the correct way to inject the header component into all routes?
Update: When I try to import the header component into app's main.js:
import Header from './components/header.vue'
Vue.component('page-header', Header);
I get this error:
Failed to mount component: template or render function not defined.
If you want to have the same header component in all routes. place it before router-view and change your css layout.
If you wan't to change the content of the header component depending on each route. You can place another <router-view name="header"> inside your header component. And then in your array of routes
<template>
<div>
<app-header><../>
<router-view><../>
</div>
</template>
Otherwise:
export default [
{
path:'/',
components: {
default: defaultComponentForThisRoute,
header: yourRouteHeaderComponent,
}
},
]

How to use component-nesting with vue-router?

I'm pretty new to Vue and I just can't find a good way how to use nested components alongside with vue-router.
What I have so far (some not-important code omitted):
index.html
<body>
<div id="app">
<router-view></router-view>
</div>
app.js
const router = new VueRouter({
routes: [{ path: '/login', component: Login }]
})
const app = new Vue({
router,
}).$mount('#app')
components/Login.vue
<template>
<h1>Please log in</h1>
</template>
This works perfectly well - I navigate to /login and it shows me the message in h1 tag. If I create more components, like Register or ResetPassword and add them to the router, it still works well. But the problem is that there is some repeating code in those components (for example, I want all the auth-related pages to have blue background) so I'd like to somehow create a "parent" component, that would define stuff that is same for all the "children" components. Something like:
Auth component (makes the page-background blue)
-> Login component (shows the login form)
-> Register component (shows the registration form)
I know I can do this through route's "children":
const router = new VueRouter({
routes: [
{ path: '/', component: Auth, children: [
{ path: '/login', component: Login }
{ path: '/register', component: Register }
]}
]
})
But with this configuration, there is the main route path: '/', which is completely wrong - I don't want it here - I don't want the Auth component to be used "standalone" - I want it just as a "wrapper" for the nested components.
What is the best way to solve this problem?
The way I've solved this issue is to use a base path redirect.
{ path: '', redirect: '/to/path' },
in your case it would be
const router = new VueRouter({
routes: [
{
path: '/',
component: Auth,
children: [
{ path: '', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/register', component: Register }
]
}
]
})
This ensures that

Can't render child component with VueRouter

I'm learning VueJS, created a new Vue app with the vue-cli, and changed it a little bit. This is what I have in my router.js:
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '#/components/Hello'
import Panel from '#/components/Panel'
import Search from '#/components/Search'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello
},
{
path: '/panel',
name: 'Panel',
component: Panel,
children: {
path: 'search',
component: Search
}
}
]
})
My Panel.vue renders properly without a 'children' key in the router object. This is the content:
<template>
<div class="panel">
<h1>Panel</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'panel',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
And Search.vue is very similar
<template>
<div class="search">
<h1>Search</h1>
<p>Lorem ipsum ...</p>
</div>
</template>
<script>
export default {
name: 'search',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
With this configuration, as explained here: https://router.vuejs.org/en/essentials/nested-routes.html
I get this error:
vue-router.common.js?37ec:598Uncaught TypeError: route.children.some is not a function
And a blank page is displayed.
I want, for example, localhost:port/#/panel to display the Panel component only (this is not so important).
And localhost:port/#/panel/search to display the Search component, that is wrapped by Panel component (this is the important part, because nobody would actually go to just /panel).
Could anybody give some help?
It's because children should be array of objects, and some is method that lives on array, so that's why you are getting error.
children: [{
path: 'search',
component: Search
}]

Categories

Resources