Vue router cannot access root app path '/' from nested view nested children - vue.js

I am trying to access root path of app '/' or named component 'Home' from nested view with nested children.
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
...
{
path: "/account",
name: "Account",
component: AccountHome,
children: [
{
name: "AccountAvatars",
path: "avatars",
component: AccountAvatar,
},
...
],
},
];
const router = new VueRouter({
mode: "history",
base: '/',
routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 };
},
});
Vue.use(VueRouter);
export default router;
....
When i want to use router-link or manually this.$router.push({name: 'Home'}) or this.$router.push({name: '/'}) from /account/avatars for example click on router-link or $router.push not working at all.
App.vue
<template>
<div id="app">
<global-header />
<router-view />
<global-footer />
</div>
</template>
Home.vue
<template>
<div class="home">
<offer />
<home-menu />
<game-catalog/>
<benefits />
<news />
</div>
</template>
AccountHome.vue
<template>
<div class="container">
<div
class="account"
>
<account-left-sidebar />
<router-view />
<account-right-sidebar />
</div>
</div>
</template>
Router instance
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 }
}
})

check what's inside BASE_URL. the .base argument of VueRouter constructor is not your app's baseUrl. it's just default path. official Vue Router doc. it should be base:'/'.
check this working code:
https://codesandbox.io/s/holy-bush-jsi79?file=/src/routes.js
Edit: I've added programmatically routing example as well.(to match your edit)
Edit 2: I've also added another running example that's exactly same to your edit. it still works. I think one of your components are fiddling with routers.
https://codepen.io/rabelais88/pen/NWjJEMe

Related

this.$route.name is undefined inside the app.vue when console it inside created()

I am using vue3 and I am a newcomer to this. With the use of vue-router I created the routes. But I want to get the this.$route.name inside the app.vue. Therefore tried to get the value inside the created method. But at the beginning that value is undefined.
You get null because $route.name is not intialized yet in the created method.
You can instead use a computed variable, so this way $route.name will be initialized.
<template>
<div class="main-view">
<Navigation v-if="enableNavigation" />
<router-view />
<Footer />
</template>
export default {
name: 'App',
computed: {
enableNavigation() {
const disabledNavRoutes = ['login', 'register', 'resetPassword'];
return disabledNavRoutes.indexOf(this.$route.name) === -1;
}
}
}
In your case you want to display the Navigation component but only in some routes (the route when the user is not authenticated i assume). Here some alternatives:
Method 1: nested routes
router.js
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/login',
name: 'login',
component: LoginView,
},
{
path: '/home',
name: 'home-shell',
component: HomeShell,
children: [
{
path: 'home',
name: 'home',
component: HomeView
},
]
},
],
});
Remove the Navigation from App.js to remove it from login / register component
App.js
<template>
<div class="main-view">
<router-view></router-view>
</div>
</template>
Put the navigation and footer component in the HomeShell
HomeShell.js
<template>
<Navigation />
<--! Nested router. In our case HomeView !-->
<router-view />
<Footer />
</template>
And the HomeView component will be injected in the router-view of the HomeShell
Method 2: v-if
An other way would be to have a variable isAuthenticated in the store and conditionally show the Navigation component in the App component
App.js
<template>
<Navigation v-if="isAuthenticated" />
<router-view />
<Footer v-if="isAuthenticated" />
</template>
...
computed: {
isAuthenticated() {
return this.$store.getters.isAuthenticated
}
The limitation here is that if later you want to disable the navigation for routes where the user can authenticated (i.e. error 404 route). This won't work anymore.
I recommend you to check out this SO question for more info

VueJS: How to make a nested router-view always render one of its routes?

TL:DR;Is it possible to make the router-view display a component without being on that component route ?
I am trying to imitate a carousel effect using router-view inside a child component.
The problem is that if I don't click on a router-link the router-view displays nothing.
I want to make on of the router-link be active when no other is in order to force the router-view to always display something.
App.vue with the top router-view:
<template>
<div id="app">
<router-view />
</div>
</template>
Router index.js:
const routes = [
{
path: "/",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "/icons",
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
scrollBehavior(to, savedPosition) {
if (to.hash) {
return {
selector: to.hash,
behavior: "smooth",
// offset: { x: 0, y: 75 }
};
} else {
return savedPosition;
}
},
});
LandingPage.vue:
<template>
<div class="page">
<Home></Home>
<About></About>
<Portfolio></Portfolio>
<Contact></Contact>
</div>
</template>
Portfolio.vue with the second router-view:
<template>
<section id="portfolio">
<ul>
<li v-for="slide in slider" :key="slide.path">
<router-link :to="`/${slide.link}`">{{ slide.text }}</router-link>
</li>
</ul>
<router-view />
</section>
</template>
As you can see I have only one route, which is / for the top router-view. This will render LandingPage.
I use hashes to navigate to the components inside LandingPage like so: <router-link :to="{ path: '/', hash: #${link.path} }">
I am trying to make the router-link :to="/icons" active and the Icons component render inside Portfolio's router-view when no other link from Portfolio is active.
It's important for it to remain active only inside Portfolio, because I have a Navbar with other router-link which go to various hashes inside LandingPage.
Is this even possible ?
If I understood, you want to show Icon when the route is '/'.
To define a default sub-route you need to have a route with an empty value (path:'').
Now if you don't want to change path use the 'alias' mechanism.
const routes = [
{
path: "/",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "/icons",
alias: '',
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];
If alias doesn't meet your needs, define your sub-route twice(One by empty path second by '/icons')
You can also define /icons as the main route:
const routes = [
{
path: "/icons",
name: "LandingPage",
component: LandingPage,
children: [
{
path: "",
name: "Icons",
component: () => import(/* webpackChunkName: "about" */ "../components/portfolio/Icons.vue"),
},
],
},
];

Why does Vue router-link not Work on Click

I have the following nav bar component which should link to my about page view. When I mouse over a router-link element I can see Chrome telling me it should go there:
But when I click a link it does not go there.
NavBar.vue component template:
<template>
<nav>
<input class="search-bar" type="text" placeholder="Search Creators..." />
<ul class="menu-div">
<router-link to="/about">Pricing</router-link>
<router-link to="/about">Hello</router-link>
<router-link to="/about">Goodbye</router-link>
<router-link to="/about">Onetwo</router-link>
<button class="sign-up">Sign Up</button>
</ul>
</nav>
</template>
Here is my app.vue template
<template>
<div id="app">
<nav-bar />
<router-view></router-view>
</div>
</template>
<script>
import NavBar from "#/components/NavBar.vue";
export default {
components: {
"nav-bar": NavBar
}
};
</script>
And my routes in my index.js
import Home from "#/views/Home.vue";
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/about",
name: "About",
component () { import("#/views/About.vue") }
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
Why is my about view not showing up when I click the router-link tags in my nav bar?
You are just importing the component. You must return it.
Change
component () { import("#/views/About.vue") }
to
component () { return import("#/views/About.vue") }
Or you could import the component outside of the definition and use it
import Home from "#/views/Home.vue";
import Vue from "vue";
import VueRouter from "vue-router";
import About from "#/views/About.vue"
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/about",
name: "About",
component: About
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
....

How to create a login screen which don't include App.vue components

I am creating a SPA which have a login screen and other views. But the problem I am facing is, the login screen view also includes in the Navigation bar but It should not be there. Then I used Router navigation which displays a navigation bar alone without any views I think it also guards the Login view also.
App.vue
<template>
<section id="app" class="hero">
<section class="main-content columns is-fullheight has-background-white-bis">
<Navigation />
<div class="hero-body">
<router-view />
</div>
</section>
</section>
</template>
<style>
.menu {
margin: 25px;
}
</style>
<script>
import Navigation from "#/components/Navigation.vue";
export default {
name: "app",
components: {
Navigation
}
};
</script>
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [{
path: '/LoginUser',
name: 'login',
component: LoginUser,
},
{
path: '/',
name: 'dashboard',
component: Dashboard,
},
}]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
var isAuthenticated = false;
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/LoginUser')
else next()
})
export default router
To remove the navigation when specifically on the Login route, you can add a v-if to your <Navigation /> component, which checks if the route is not on the login page:
<Navigation v-if="this.$router.currentRoute.name !== 'login'" />
We can conditionally render components by checking the name of the current route using v-if directive. I used this in a recent project.
My route index.js file
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/register',
name: 'register',
component: Register
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
My App.vue file
<template>
<div id="app">
/* Note that this takes an array of route names, so you can simple pass in
the name of the route you dont want this component to be displayed on */
<navbar v-if="!['login', 'register', 'help'].includes($route.name)" />
<main>
<router-view />
</main>
<appfooter v-if="!['login', 'register'].includes($route.name)"/>
</div>
</template>

vue-router navigate to the same route and re-run mounted hook

How can I naviagte to the current route using router-link and re-run mounted hook?
HTML
<!-- Include the library in the page -->
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router"></script>
<!-- App -->
<div id="app">
<nav>
<router-link :to="{ name: 'home' }" exact>Home</router-link>
<router-link :to="{ name: 'about' }" #click.native.prevent="router.push({ name: 'about' })">About</router-link>
</nav>
<router-view :key="$route.fullPath"></router-view>
</div>
JS
console.clear()
console.log('Yes! We are using Vue version', Vue.version)
Vue.use(VueRouter)
const Home = {
template: `<h1>Home</h1>`,
}
const About = {
template: `<h1>{{new Date()}}</h1>`,
mounted(){
console.log('mounted')
}
}
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
]
const router = new VueRouter({
routes,
})
// New VueJS instance
var app = new Vue({
// CSS selector of the root DOM element
el: '#app',
// Inject the router into the app
router,
})
In the above example, if I navigate to 'About' it shows the timestamp from new Date and logs 'mounted'. However, if I'm already on /about, clicking the about link does nothing. I want to re-run the whole component lifecycle when clicking 'About', even if I'm already hit it.
You'll need to change the key in the <router-view> element whenever the user clicks your about page, that will force the mounted hook:
<template>
<div id="app">
<router-link #click.native="updateViewKey" :to="{ name: 'about' }">About</router-link>
<router-view :key="viewKey"></router-view>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
viewKey: 1
};
},
methods: {
updateViewKey() {
this.viewKey+=1;
}
}
};
</script>
Try this :
router.push({
name: 'routeName',
params: {
id: 'new value'
}
})