Vue router inside component doesn't redirect - javascript

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>

Related

Ionic Vue components get stack on top of each other when using router

I have a problem, where when I use Vue Router for navigation, components don't disappear, the new one just places on top of old one.
My router file
import {createRouter, createWebHistory} from '#ionic/vue-router';
import {RouteRecordRaw} from 'vue-router';
import {AuthManager} from "#/functions/AuthManager";
import HomePage from '#/views/MainPage.vue';
import LoginScreen from '#/views/auth/LoginScreen.vue';
import component from "*.vue";
import RegistrationScreen from "#/views/auth/RegistrationScreen.vue";
import MainPage from "#/views/MainPage.vue";
const routes: Array<RouteRecordRaw> = [
{
path: '',
redirect: '/homepage',
},
{
path: '/login',
name: 'Login',
component: LoginScreen,
meta: {
requiresAuth: false
}
},
{
path: '/register',
name: 'Register',
component: RegistrationScreen,
meta: {
requiresAuth: false
}
},
{
path: '/home',
name: 'MainPage',
component: MainPage,
meta: {
requiresAuth: true
}
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
//code from https://stackoverflow.com/a/52663166 and modified to fit my needs
router.beforeEach(async (to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!await AuthManager.isLoggedIn() && to.name != "Login") {
next({name: 'Login', hash: '#forced'});
} else if ((to.name == "Login" || to.name == "Register") && await AuthManager.isLoggedIn()) {
next({name: 'Homepage'});
} else {
next() // go to wherever I'm going
}
} else {
next() // does not require auth, make sure to always call next()!
}
})
export default router
How I navigate
<ion-text #click="() => router().push('/register')" style="cursor: pointer" class="ion-padding-top">Nemáte účet? Zaregistrujte se</ion-text>
Image of components stacked on top of each other
I can't find a way to make old component disappear. Where Am I doing something wrong?

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
},
]
}
…

Vue nested routes not displaying their components and no errors

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'}
]},
];

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