Vue nested routes not displaying their components and no errors - javascript

When I access URL profile/admin, I see the profile component, however, if I try URL profile/admin/locations or profile/admin/map, I don't load the Map or Locations components. Any ideas why?
The routes in question:
import Home from './components/Home.vue';
import Profile from './components/Profile.vue';
import Map from './components/Map.vue';
import Locations from './components/Locations.vue'
export const routes = [
{ path: '', component: Home, name: 'Home'},
{ path: '/profile/:username', component: Profile, name: 'Profile', chilren: [
{ path: '/profile/:username/locations', component: Locations, name: 'Locations'},
{ path: '/profile/:username/map', component: Map, name: 'Map'}
]},
];
Profile component template:
<template>
<div class="wrapper">
<p>Profile</p>
<router-view></router-view>
</div>
</template>
Location component template:
<template>
<div class="wrapper">
<p>Location</p>
</div>
</template>
Map component template:
<template>
<div class="wrapper">
<p>Location</p>
</div>
</template>

You have a typo in your routes - chilren instead of children.
You don't need to specify full path in children routes. Correct way of doing:
export const routes = [
{ path: '', component: Home, name: 'Home'},
{ path: '/profile/:username', component: Profile, name: 'Profile', children: [
{ path: 'locations', component: Locations, name: 'Locations'},
{ path: 'map', component: Map, name: 'Map'}
]},
];

Related

Issue when trying to use Nested routes in Vuejs?

main.js
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import User from "./components/User";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{
path: "/",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App)
}).$mount("#app");
HelloWorld.vue
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link :to="`/HelloWorld/${item.id}`">
{{ item.title }}
</router-link>
</div>
<!-- end v-for -->
<router-view></router-view>
</div>
</template>
<script>
import { router } from "./router";
export default {
name: "HelloWorld",
components: {},
data() {
return {
items: [],
};
},
mounted() {
router().then((r) => {
this.items = r.data;
});
},
};
</script>
codesandbox:- https://codesandbox.io/s/combined-logic-api-forked-oq808t?file=/src/main.js
in main.js routing file, if i change from path:'/' to path:'/HelloWorld' then output is not displaying. Not sure why and where it is linked with api call..
The reason why i changed from path:'/' to path:'/HelloWorld' because path:'/' in my project, it will consider as login page. So tried changing but getting blank screen.
You should change
const router = new VueRouter({
routes: [
{
path: "/HelloWorld/",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
to
const router = new VueRouter({
mode: 'history',
routes: [
{
path: "/HelloWorld/",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
(So, add mode: history, to the router.)
More on mode: history in Vue Router v3 here

Display layout based on boolean from Vuex

I got Vue2 app with vue-router with routings configured like that:
export default {
path: "/",
redirect: "/dashboard",
component: AdminLayout,
meta: {
requiresAuth: true
},
children: [
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard
},
{
path: "/add/user",
name: "InviteUser",
component: InviteUser
},
{
path: "/groups",
name: "Groups",
component: Groups
},
...
In app, we got two different types of users - admin and normal user. Some of those routings should be accessible for both, but the problem is that user should see different layout base on its type (permission) - AdminLayout for admins and UserLayout for normal users.
Is there any way to show app which template should user see based on boolean from vuex with keeping route path?
on /dashboard admin will see dashboard with AdminLayout
on /dashboard normal user will see dashboard with UserLayout
My main routing cofig:
import Vue from "vue";
import VueRouter from "vue-router";
import SessionRoutes from "./session.js";
import AdminRoutes from "./admin.js";
import defaultRoutes from "./default";
Vue.use(VueRouter);
const routes = [AdminRoutes, SessionRoutes, defaultRoutes];
const router = new VueRouter({
mode: "history",
routes
});
export default router;
you can set a condition in the layout part on the current page for example for when you use nuxt:
<script>
export default {
layout: (ctx) => (ctx.isAdmin ? 'adminLayout' : 'userLayout'),
}
</script>
but I opine you don't use Nuxt.js and I think below solution is suitable for your question:
Using the meta-object in our route
set dynamic component on app.vue page
code for about.vue page
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import LayoutA from '../layouts/LayoutA.vue'
import LayoutB from '../layouts/LayoutB.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: { layout: LayoutA }
},
{
path: '/about',
name: 'About',
component: About,
meta: { layout: LayoutB }
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router;
<!--app.vue page -->
<template>
<div id="app">
<component :is="this.$route.meta.layout || 'div'">
<router-view />
</component>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<!--about page-->
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script>
export default {
name: "About"
};
</script>
To get a different layout working for the dashboard and all child routes your layouts have to use the router view component. I use a wrapper component to handle this in one of my projects following this approach.
Excerpt from my router config:
…
{
component: MainFrame,
name: 'main',
path: '/',
redirect: 'dashboard',
children: [
{
alias: 'dashboard',
component: Dashboard,
name: 'dashboard',
path: '', // Default child route → be equivalent to /dashboard
},
{
path: "add/user",
name: "InviteUser",
component: InviteUser
},
{
path: "groups",
name: "Groups",
component: Groups
},
],
},
…
In your MainFrame component you can wrap your layout in a dynamic component. So you can switch your layout easely based on a Vuex getter:
MainFrame.vue
<template>
<component :is="layout">
<!-- you can use slots too if you like -->
</component>
</template>
<script>
import AdminLayout from './AdminLayout'
import UserLayout from './UserLayout'
export default {
computed: {
layout() {
return this.$store.getters['isAdminUser'] ? AdminLayout : UserLayout
}
}
}
</script>
And your layouts have to use <router-view />. It works as a wrapper for all nested routes and therefore you have only one place to handle the layout for the dashboard and child pages:
AdminLayout.vue
<template>
<div class="auth-view">
<header>…</header>
<aside>…</aside>
<main>
<transition name="fade" mode="out-in">
<router-view />
</transition>
</main>
<footer>…</footer>
</div>
</template>
UserLayout.vue
<template>
<div class="guest-view">
<router-view />
</div>
</template>
EDIT:
This approach can be used for deeper nesting too. Assuming your user route should have another child routes you can solve this on the router config using a <router-view /> within a render function:
…
// Let's split down user related routes
{
component: { render: (h) => h('router-view') },
name: 'usersView',
path: 'users',
redirect: 'ListUsers',
children: [
// Show users
{
path: '', // route: /users/
name: 'ListUsers',
component: ListUsers
},
// Show a single user
{
path: ':id', // route: /users/{userId}
name: 'ViewUser',
component: ViewUser
},
// Invite new users
{
path: 'add', // route: /users/add
name: 'InviteUser',
component: InviteUser
},
]
}
…

Angular 9 use two different layouts in the same application

My application contains two different layouts. One layout is the application where we show the top navigation and a sidebar.
<app-nav></app-nav>
<div>
<app-sidebar></app-sidebar>
<router-outlet></router-outlet>
</div>
and the second layout is the login and signup pages where we don't have the navigation bar and sidebar.
The naive solution will be to add ngIf to both elements based on the current route. But I prefer avoiding it. The reason is that we have code inside these components that we don't want to load where we don't need to.
Is there any better solution to this issue?
Have the AppComponent contain an router-outlet as the template.
#Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor() {
}
}
Then include routes as:
const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: AppComponent,
canActivate: [LanguageGuard]
},
{
path: ':lang',
component: LanguageComponent,
children: [
{
path: 'partner',
loadChildren: () => import('./partner/partner.module').then(m => m.PartnerModule)
},
...ClientRoutes,
...AuthRoutes
]
}
];
My project have different layouts for the partner and ClientRoutes/AuthRoutes
Partner:
const routes: Routes = [{
path: '',
component: PartnerLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'profile',
component: ProfileComponent
}
]
}];
This is the content of ClientRoutes/AuthRoutes:
export const ClientRoutes: Routes = [{
path: '',
component: ClientLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'sofa',
component: SofaComponent
}
]
}];
Then you change my PartnerModule as your login module and lazy load it.
But don't every user need to login? Maybe only put the signup process in that module.
If you're lazy-loading your modules, it's easy:
Add a second "layout" page with a <router-outlet>
In your routes, define your route like this:
const routes:Routes=[{path:'some-path', component: YourLayoutComponent, loadChildren: ()=> import('./lazy-loaded-module/lazy-loaded.module').then(m=>m.LazyLoadedModule) }];

Vue router inside component doesn't redirect

I have two main pages, one is landing with login/register forms and one is with navbar and content. After login/register I get redirected to /main. There in named route "nav" I load navbar and in "con" content gets loaded. Router-links are inside navbar which is separate component. Now when I click on one of the links nothing happens, but if I enter URL manually it work fine. My guess is that problem is that this is inside a component or something.
Link inside navbar component:
<router-link :to="{ name: 'forum' }">
<b-nav-item href="#" ><i class="material-icons md-36">forum</i> Forum</b-nav-item>
</router-link>
My view
<div id="app">
#csrf
<router-view></router-view>
<router-view class="view one" name="nav"></router-view>
<router-view class="view two" name="con"></router-view>
</div>
And my App.js with routes
import Landing from './components/LandingPage.vue'
import Home from './components/HomePage.vue'
import Navbar from './components/Navbar.vue'
import Forum from './components/Forum.vue'
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Landing,
meta: {
requiresVisitor: true,
}
},
{
path: '/main',
name: 'main',
components: {
nav: Navbar,
con: Home
},
meta: {
requiresAuth: true,
}
},
{
path: '/forum',
name: 'forum',
components: {
nav: Navbar,
con: Forum
},
meta: {
requiresAuth: true,
}
}
],
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.loggedIn) {
next({
name: 'home',
})
} else {
next()
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
if (store.getters.loggedIn) {
next({
name: 'main',
})
} else {
next()
}
} else {
next()
}
})
const app = new Vue({
el: '#app',
components: { Home, Landing, Navbar, Forum },
router,
store,
});
I have imported VueRouter, but didn't add it to the code to make it more simple
The problem is the href-attribute inside the router link (b-nav-item href="#").
Omitting the href-attribute does solve the problem.
<router-link :to="{ name: 'forum' }">
<b-nav-item><i class="material-icons md-36">forum</i> Forum</b-nav-item>
</router-link>

VueJS named routes not working

I try to work with named routes in a Vue app.
Exactly the same setup works totally fine in an other Vue project.
If I click on a named router-link, the just disappears.
If I check the element in the browser, there is an empty comment at the place, where the section should be.
The console isn't showing any errors.
Has anyone seen something similar?
Thank's for every help!
Code:
index.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '#/components/views/home';
import AskQuestion from '#/components/views/ask-question';
import AddQuestion from '#/components/views/add-question';
import CompleteQuestions from '#/components/views/complete-questions';
import Survey from '#/components/views/survey';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/ask-question',
name: 'AskQuestion',
component: AskQuestion
},
{
path: '/add-question',
name: 'AddQuestion',
component: AddQuestion
},
{
path: '/complete-questions/:surveyId',
name: 'CompleteQuestions',
component: CompleteQuestions
},
{
path: '/survey/:surveyId',
name: 'Survey',
component: Survey
}
]
});
HTML
<router-link :to="{name: 'survey', params: {surveyId: survey.id}}">
<p class="viewQuestions">View questions</p>
</router-link>
App.vue
<template>
<div id="app">
<navigation></navigation>
<router-view/>
</div>
</template>
<script>
import Navigation from '#/components/generel/navigation';
export default {
name: 'app',
components: {
Navigation
}
};
</script>
<style src="./assets/scss/_general.scss" lang="scss"></style>
in route config , set history mode and then go to your link and click that LINK , and then go check URL address bar
export default new VueRouter({
mode:'history',
......
});
for example if you click on this
<router-link :to="{ name: 'home' }"> Home </router-link>
and your rute is
{
path:'/home',
component:Home,
name:'home'
}
if your route workin well , you must see this url in browser address bar
https://localhost/home

Categories