Vue router id gets undefined when taken from vuex - vue.js

I am trying to get the id of currently logged user from Vuex getters and pass it into the router link, but somehow it gets undefined, even though I console.log it and it shows legitimate user ID. In my template. Here I loop over an array of objects where I keep my route name:
<v-list dark class="mt-5 userList" style="background: #515151;">
<v-list-item
v-for="item in sideBar"
:key="item.title"
class="tile"
>
<router-link :to="item.route">
<span class="userIcon">
<v-list-item-icon>
<v-icon style="color: #FFA255">{{ item.icon }}</v-icon>
</v-list-item-icon>
</span>
<span class="userTitle">
<v-list-item-content>
<v-list-item-title style="color: #FFA255">
{{ item.title }}
</v-list-item-title>
</v-list-item-content>
</span>
</router-link>
</v-list-item>
</v-list>
I think this part speaks for itself My script section:
export default {
data() {
return {
userParams: null,
sideBar: [
{title: 'User', icon: 'note', component: 'UserInfo', route: `/user/${this.userParams}`},
{title: 'Rated albums', icon: 'note', component: 'Rated', route: `/user/${this.userParams}/rated`},
{title: 'Owned', icon: 'favorite', component: 'Owned', route: `/user/${this.userParams}/owned`},
{title: 'Settings', icon: 'settings', component: 'Settings', route: `/user/'${this.userParams}'/settings`},
],
}
},
computed: {
...mapGetters([
'getUserId'
])
},
created() {
this.userParams = this.getUserId;
console.log(this.userParams)
},
}
My router.js
{
path: '/user/:id',
component: User,
children: [
{
path: '/',
component: UserInfo,
name: 'userInfo'
},
{
path: 'owned',
component: Owned,
name: 'owned'
},
{
path: 'rated',
component: Rated,
name: 'rated'
},
{
path: 'settings',
component: Settings,
name: 'settings'
}
],
beforeEnter (to, from, next) {
if(authStore.state.idToken) {
next()
} else {
next('/signin')
}
}
},

Make sideBar a computed property so it is re-evaluated when getUserId changes.
I don't see a reason to keep a copy of getUserId in userParams either.
computed: {
...mapGetters([ 'getUserId' ]),
sideBar () {
const params = { id: this.getUserId } // this is reactive
return [{
title: 'User',
icon: 'note',
route: { name: 'userInfo', params }
}, {
title: 'Rated albums',
icon: 'note',
route: { name: 'rated', params }
}, {
title: 'Owned',
icon: 'favorite',
route: { name: 'owned', params }
}, {
title: 'Settings',
icon: 'settings',
route: { name: 'settings', params }
}]
}
},
At the moment, your route strings are only calculated once when your component is created

Related

Navbar selects two drawers at once if one path contains the other in Vue

I'm creating an application in Vue.js with a sidebar.
In v-list-item, in the path :to="link.route", I'm using the names for routes: { name: "dashboard" }.
The problem occurs when the path to one link is contained in a link to the other path.
Eg. path: '/' (dashboard) is contained in path: '/help'.
If I click on Help, then both sidebar drawers are selected:
Template:
<template>
<div>
<v-navigation-drawer v-model="drawer">
<v-list nav dense>
<v-list-item-group>
<v-list-item
v-for="link in links"
:key="link.text"
:to="link.route">
<v-list-item-content>
<v-list-item-title class="white--text">{{
link.text
}}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
</div>
</template>
Script:
<script>
export default {
data: () => ({
drawer: true,
}),
computed: {
links() {
return [
{
text: "Dashboard",
route: { name: "dashboard" },
},
{
text: "Help",
route: { name: "help" },
},
];
},
},
};
</script>
Router:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Dashboard from '../views/Dashboard.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'dashboard',
component: Dashboard
},
{
path: '/help',
name: 'help',
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
I fixed my problem by adding path { name: "dashboard", path:'/' }in dashboard route declaration.
Code before:
links() {
return [
{
text: this.$i18n.t("navbar.dashboard"),
route: { name: "dashboard"},
},
{
text: this.$t("navbar.help"),
route: { name: "help"},
},
];
},
Code after:
links() {
return [
{
text: this.$i18n.t("navbar.dashboard"),
route: { name: "dashboard", path:'/' },
},
{
text: this.$t("navbar.help"),
route: { name: "help"},
},
];
},
It's not exactly what I wanted, but it solves the problem.

vuetify and vue-router active navbar for multiple tabs

I would like to achieve highlighting the same menu in a navbar while browsing different tabs.
As seen on the image above, belong is selected while on the department tab. I still wanted to highlight the belong menu while selecting the selection tab. Please see my code below.
Navbar component
<v-list dense>
<v-list-item v-for="item in items" :to="item.to" :key="item.title" link>
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<script>
export default {
data () {
return {
drawer: true,
items: [
{ to: { name: 'dashboard'}, title: 'Dashboard', icon: 'mdi-account' },
{ to: { name: 'department'}, title: 'Department', icon: 'mdi-home-city' },
{ to: { name: 'salary'}, title: 'Salary', icon: 'mdi-cash' },
],
mini: false,
}
},
}
</script>
Router Tab Component
<template>
<v-tabs class="mb-2" mobile-break-point="200px">
<v-tab v-for="tab in navbarTabs"
:key="tab.id"
:to="tab.to"
>
{{ tab.name }}
</v-tab>
</v-tabs>
</template>
<script>
export default {
data() {
return {
navbarTabs: [
{
id: 0,
name: "Department",
to: { name: 'department' }
},
{
id: 1,
name: "Section",
to: { name: 'section' }
},
]
}
}
}
</script>
Routes.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import Dashboard from './views/Dashboard'
import Department from './views/Department'
import Section from './views/Section'
import Salary from './views/Hello'
export const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/dashboard', name: 'dashboard', component: Dashboard },
{ path: '/belong/department', name: 'department', component: Department},
{ path: '/belong/section', name: 'section', component: Section },
{ path: '/salary', name: 'salary', component: Salary},
],
});
The current setup is that department path is connected to the belong menu, but I wanted to make it a dynamic wherein section tab will also set the navbar belong into active.
Both of these components are inside the App.vue (main vue file for routing)
UPDATE: I have now fixed this issue.
Here is what I did with the router.js
export const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/404', component: NotFound },
{ path: '*', redirect: '/404' },
{ path: '/', redirect: '/dashboard' },
{ path: '/dashboard', name: 'dashboard', component: Dashboard },
{ path: '/org', name: 'organization', component: Organization,
children: [
{ path: 'department', name: 'department', component: Department},
{ path: 'section', name: 'section', component: Section },
{ path: 'position', name: 'position', component: Position }
],
},
{ path: '/salary', name: 'salary', component: Salary},
],
});
I created a parent component (organization) that holds all the other sub components (department, section, position) and set them as children.
If there are other best practices to do this, please feel free to share your knowledge.

route.params has properties that don't match dynamic url

I want to ask about vue-router. This is my first time using vue js.
Initially I was on the route:
localhost: 8080 / article / edit-article / 2
and when I move to route:
localhost: 8080 / page
this is still running.
But when I moved from:
localhost: 8080 / article / edit-article / 2
to:
locahost: 8080 / dashboard
the route instead changed to:
localhost: 8080 / article / edit-article / dashboard
not:
localhost: 8080 / dashboard
This my vue-router:
export default new Router({
mode: 'history',
linkActiveClass: 'open active',
scrollBehavior: () => ({ y: 0 }),
routes: [
{
path: '/',
redirect: '/login',
name: 'Home',
component: DefaultContainer,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: Dashboard,
meta: {
requiresAuth: true
}
},
{
path: 'page',
name: 'Page',
component: Page,
meta: {
requiresAuth: true
}
},
]
},
{
path: '/article',
component: DefaultContainer,
meta: {
requiresAuth: true
},
children: [
{
path: '',
name: 'List Articles',
component: Article,
meta: {
requiresAuth: true
}
},
{
path: 'add-article',
name: 'Add Article',
component: AddArticle,
meta: {
requiresAuth: true
}
},
{
path: 'edit-article/:id',
name: 'Edit Article',
component: EditArticle,
meta: {
requiresAuth: true
}
},
]
},
{
path: '/login',
name: 'Login',
component: Login,
meta: {
requiresVisitor: true
}
},
]
})
I use navbar with js, like this:
export default {
items: [
{
name: 'Dashboard',
url: 'dashboard',
icon: 'icon-speedometer',
},
{
name: 'Article',
url: 'article',
icon: 'icon-note'
},
{
name: 'Page',
url: '/page',
icon: 'icon-layers'
},
]
}
and this my DefaultContainer:
<template>
<div class="app">
<AppHeader fixed>
<SidebarToggler class="d-lg-none" display="md" mobile />
<b-link class="navbar-brand" to="/dashboard">
<img class="navbar-brand-full" src="img/brand/logo.svg" width="89" height="25">
<img class="navbar-brand-minimized" src="img/brand/sygnet.svg" width="30" height="30>
</b-link>
<SidebarToggler class="d-md-down-none" display="lg" />
<b-navbar-nav class="ml-auto">
<DefaultHeaderDropdownAccnt/>
</b-navbar-nav>
</AppHeader>
<div class="app-body">
<AppSidebar fixed>
<SidebarHeader/>
<SidebarForm/>
<SidebarNav :navItems="nav"></SidebarNav>
<SidebarFooter/>
<SidebarMinimizer/>
</AppSidebar>
<main class="main">
<Breadcrumb :list="list"/>
<div class="container-fluid">
<router-view></router-view>
</div>
</main>
<AppAside fixed>
<!--aside-->
<DefaultAside/>
</AppAside>
</div>
<TheFooter>
<!--footer-->
<div>
<span class="ml-1">© 2019 local Incorporation. All Rights Reserved</span>
</div>
</TheFooter>
</div>
</template>
<script>
import nav from '#/_nav'
import { Header as AppHeader, SidebarToggler,` `Sidebar as AppSidebar, SidebarFooter, SidebarForm, SidebarHeader, SidebarMinimizer, SidebarNav, Aside as AppAside, AsideToggler, Footer as TheFooter, Breadcrumb } from '#coreui/vue'
import DefaultAside from './DefaultAside'
import DefaultHeaderDropdown from './DefaultHeaderDropdown'`
export default {
name: 'DefaultContainer',
components: {
AsideToggler,
AppHeader,
AppSidebar,
AppAside,
TheFooter,
Breadcrumb,
DefaultAside,
DefaultHeaderDropdown,
SidebarForm,
SidebarFooter,
SidebarToggler,
SidebarHeader,
SidebarNav,
SidebarMinimizer
},
data () {
return {
nav: nav.items
}
},
computed: {
name () {
return this.$route.name
},
list () {
return this.$route.matched.filter((route) => route.name || route.meta.label )
}
}
}
</script>
Thanks all
It seems likely that the problem is here:
url: 'dashboard',
This would appear to be a relative path. So if you are currently on the page http://localhost:8080/article/edit-article/2 it will resolve relative to that URL, giving http://localhost:8080/article/edit-article/dashboard. This isn't really anything to do with Vue router, it's just how relative URLs are resolved. You'd get exactly the same behaviour if you used an HTML link such as <a href="dashboard">.
If you start your relative URL with a / then it will omit the rest of the path:
url: '/dashboard',
This should fix your problem. This is what you've done with your /page URL, which is presumably why that works.
Personally I would use named routes instead, rather than trying to craft relative URLs. See https://router.vuejs.org/guide/essentials/named-routes.html

Vue.js vuetify i18n : How to translate dynamically the Toolbar items?

I don't have any problem in localizing the components and views strings but I am lock into finding a way to localize dynamically the Toolbar items ( and of course the same items in the navigation drawer..
Currently they are displayed in App.vue as menuItems[i].title
<v-toolbar-items class="hidden-xs-only">
<v-btn flat :to="menuItems[0].link">
<v-icon left>{{ menuItems[0].icon }}</v-icon>
<span>{{ menuItems[0].title }}</span>
</v-btn>
with the script:
<script>
export default {
data () {
return {
appName: 'myAPP',
sideNav: false,
menuItems: [
{ icon: 'home', title: 'Home', link: '/home' },
{ icon: 'info', title: 'About', menu: [{ title: 'Company', link: '/company' }, { title: 'Office', link: '/office' }] },
{ icon: 'people', title: 'Members', menu: [], link: '/members' },
{ icon: 'local_library', title: 'Blog', link: '/blog' },
{ icon: 'local_grocery_store', title: 'Shopping', link: '/shopping' }
]
}
},
methods: {
switchLocale: function (newLocale) {
this.$store.dispatch('switchI18n', newLocale)
}
}
}
</script>
Should I use a computed value ? or use directly $t() in the template ?
feedback, advices and links appreciated
UPDATE
main.js
Vue.filter('translate', function (value) {
if (!value) return ''
value = 'lang.views.global.' + value.toString()
return i18n.t(value)
})
locales/i18n/en_US
{
"views": {
"global": {
"Home": "Home",
"Section1": "Section 1",
..
Vue provides filter to help us to format the common text.
So I think it will be one of your choices.
You can click above link to follow the guide to set up your filters.
Edit:
I just realized Vue-filters should not be dependent on this context as the Vue author said. So updated my answer as below:
Then the codes will be like below:
// create vue-i18n instance
const i18n = new VueI18n({
locale: getDefaultLanguage(),
messages: langs
})
// create global filter
Vue.filter('myLocale', function (value) {
return i18n.t(value)
})
In your views or components:
<template>
<v-toolbar-items class="hidden-xs-only">
<v-btn flat :to="menuItems[0].link">
<v-icon left>{{ menuItems[0].icon }}</v-icon>
<span>{{ menuItems[0].title | myLocale }}</span>
</v-btn>
</template>
<script>
export default {
data () {
return {
appName: 'myAPP',
sideNav: false,
menuItems: [
{ icon: 'home', title: 'Home', link: '/home' },
{ icon: 'info', title: 'About', menu: [{ title: 'Company', link: '/company' }, { title: 'Office', link: '/office' }] },
{ icon: 'people', title: 'Members', menu: [], link: '/members' },
{ icon: 'local_library', title: 'Blog', link: '/blog' },
{ icon: 'local_grocery_store', title: 'Shopping', link: '/shopping' }
]
}
},
filters: {
myLocaleWhichNotWork: function (value) {
return this.$t(value) // this won't work because filters should not be dependent on this context
}
}
}
</script>

Vue-router issue with loading child component

I have an issue.
I have a router like this with child.
{
component: () => import('#/components/roles/Index'),
path: '/roles',
name: 'roles.index',
meta: {
auth: true,
roles: ['admin']
},
children: [{
component: () => import('#/components/roles/Show'),
path: ':id',
name: 'roles.show',
meta: {
auth: true,
roles: ['admin']
}
}]}
When i click on button the url is changing but component is not loading.
<v-btn icon class="mx-0" :to="{ name: 'roles.show', params: { id: props.item.id }}">
<v-icon color="blue">info</v-icon>
</v-btn>
But when i do this like that everything work right
{
component: () => import('#/components/roles/Index'),
path: '/roles',
name: 'roles.index',
meta: {
auth: true,
roles: ['admin']
}
},
{
component: () => import('#/components/roles/Show'),
path: '/roles/:id',
name: 'roles.show',
meta: {
auth: true,
roles: ['admin']
}
}
Logically a path cannot contain param only. path: ':id' will match everything, which is problematic.