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

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

Related

Vue router cannot access root app path '/' from nested view nested children

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

Vue: computed property in parent not called

In Vue 3 i have a problem calling a computed property. I need to show a component if a user sign in correctly.
In my App.vue i have:
<template>
<div class="wrapper">
<Sidebar v-if="authorized"/>
</div>
<main class="content">
<router-view />
</main>
</template>
<script>
import Sidebar from "#/components/Sidebar.vue";
export default {
name: "App",
components: {
Sidebar
},
computed: {
authorized: () => {
//some code
}
},
};
For example, when i go to /login path, the authorized computed property is called.
Then, in my Login.vue component, i have a method with:
this.$router.push({ name: 'Dashboard' })
The problem is that after the router.push, the computed property in App vue parent isn't called.
Why?

How to pass state and events handlers as props to children components with Vue.js's Router?

Before using routing, I had the following Dashboard component:
<template>
<div>
<RegistrationForm v-on:add-employee="addEmployee" />
<EmployeeTable
v-bind:employees="employees"
v-on:delete-employee="deleteEmployee"
/>
</div>
</template>
<script>
...
export default {
components: {
EmployeeTable,
RegistrationForm
},
data() {
return {
employees: []
};
},
methods:{
deleteEmployee() {...}
addEmployee() {...}
}
}
</script>
I want to have to separate routes one for registering a new employee and one for listing all employees, so what I did first is updating the above template:
<template>
<div>
<router-view/>
</div>
</template>
Then I defined a router object:
export default new Router({
mode: 'history',
routes: [
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
children: [
{
path: 'add-employee',
component: RegistrationForm,
},
{
path: 'list-employees',
component: EmployeeTable,
}
]
}
]
});
My question is how to pass the employees state variable and deleteEmployee, addEmployee methods from the Dashboard component to its children components?
Update:
I do not know why I did not receive any response on this question, although this is a common and trivial task to do in other frameworks, for instance in React:
...
export default function BasicExample() {
const [x, setX] = useState("World");
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
</ul>
<Switch>
<Route exact path="/">
<Home x={x}/>
</Route>
</Switch>
</div>
</Router>
);
}
function Home({x}) {
return (
<div>
<h2>Hello {x}</h2>
</div>
);
}
After using Vue-router for a short period of time, I concluded that this is not a limitation, but more like a design decision:
React-router: is more like a condional renderer, e.i from within the parent component and based on the current path, render the apporopriate child.
Vue-router: is more like a wiring solution.
Also I have to say: a similar behavior to React-router can be achieved using Vue-router. This by combining the router's currentRoute property with the v-if directive, which truly insert/remove a component from the DOM (not hiding it using css as v-show do).
Finally: seprating routes configuration is advantegeous, as it yield more modular project and better SPA. Of-course this separation can be done in both Vue-router and React-router (look here for React-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 not recognizing child component of View

The router does not load the components inside my view...
this is the structure:
the view: (test works, finMain does not)
<template>
<div>
<finMain></finMain>
<p>test</p>
</div>
</template>
<script>
export default {
name: 'FinView',
component: {
finMain: () => import("../components/finance/finMain"),
}
};
</script>
the router:
export default new Router({
routes: [
{
path: "/financial",
name: "financial",
component: () => import("#/views/finView")
}
],
});
if i put component: () => import("../components/finance/finMain") in my router it works... but not if I wrap the component inside the View..
This is the error i get:
Unknown custom element: <finMain> - did you register the component correctly?
For recursive components, make sure to provide the "name" option.
found in
---> <FinView>
<VApp>
<App> at src/App.vue
<Root>
I think that it's just misspelling, change component: { to components: {.