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

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>

Related

VueJS SideMenuBar component

I am using SideMenuBar from https://www.npmjs.com/package/vue-sidebar-menu to generate a side menu for my app. The elements in the bar should be dynamic based on whether the person is logged-in. The problem I have is that when I login, the items arent reactive - I need to refresh my browser for the menu to refresh. Any idea what I am doing wrong?
<div id="app">
<sidebar-menu :menu="dynamicMenu" #toggle-collapse="onToggleCollapse" #item-click="onItemClick" :collapsed="collapseMenu" >
</sidebar-menu>
<router-view />
computed: {
isAuthorized: function() {
return UserStorageService.GetUser() === null ? false : true;
},
dynamicMenu() {
return [
{
header: true,
title: "Menu",
hiddenOnCollapse: true
},
{
href: { path: "/" },
title: "Home",
icon: "fas fa-home"
},
{
href: { path: "/Dashboard" },
title: "Dashboard",
icon: "fas fa-folder",
hidden: !this.isAuthorized
},
{
href: { path: "/" },
title: "Reporting",
icon: "fas fa-archive",
hidden: !this.isAuthorized
},
{
href: { path: "/" },
title: "My profile",
icon: "fas fa-share-alt",
hidden: !this.isAuthorized
}
]
}
},
When I sign-in, the value of "isAuthorized" should change to true. That value should then be assigned to my dynamic menu (the inverse) and should toggle the menu option hidden/not-hidden.

How to get data to Quasar tree node from local JSON file

I am very new to Quasar, I want to display Quasar tree nodes from a Local JSON file and with on click of a particular node item I want to show some text.
As of now I am using Quasar tree like this.
<template>
<q-page class="flex fixed-left">
<q-tree
:nodes="simple"
node-key="label"
no-connectors
:expanded.sync="expanded"
text-color="blue"
></q-tree>
</q-page>
</template>
<style>
</style>
<script>
export default {
name: 'HelloWorld',
data () {
return {
expanded: [ 'Resources' ],
simple: [
{
label: 'Resources',
children: [
{
label: 'Projects',
children: [
{
label: 'Data sets' ,
children: [
{
label: 'Items',
}
]
},
{ label: 'Good recipe' }
]
},
{
label: 'Good service (disabled node with icon)',
icon: 'room_service',
disabled: true,
children: [
{ label: 'Prompt attention' },
{ label: 'Professional waiter' }
]
},
{
label: 'Pleasant surroundings (with icon)',
icon: 'photo',
children: [
{
label: 'Happy atmosphere (with image)',
img: 'https://cdn.quasar.dev/img/logo_calendar_128px.png'
},
{ label: 'Good table presentation' },
{ label: 'Pleasing decor' }
]
}
]
}
]
}
}
}
</script>
It was coming like this
Now I wanted to get these nodes from a local JSON file and on click on Items should display some text .
Please help me with this.
To import JSON in ECMAScript:
If you don't have a lot of JSON files and you have the permission to modify and convert them into JS files, you can follow this answer: https://stackoverflow.com/a/39855320/3241933
Then you should import the vanilla JS object into data().
Example solution:
<template>
<q-page class="flex fixed-left">
<q-tree
:nodes="simple"
node-key="label"
no-connectors
:expanded.sync="expanded"
text-color="blue"
></q-tree>
</q-page>
</template>
<style>
</style>
<script>
import jsonData from './data.js'
export default {
name: 'HelloWorld',
data () {
return {
expanded: [ 'Resources' ],
simple: jsonData
}
}
}
</script>
Make sure that your import is an array of object.

Vue router id gets undefined when taken from vuex

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

How to add a submenu to a structure like this in the description - Vue, Quasar

I am trying to add a submenu from a javascriot file.
Default menu works perfectly, but I don't know if it is possible to assign a submenu using that same structure.
export const getTabsMdl = () => {
let r = null
r = [
{ name: 'Saldo', icon: 'receipt', to: '/saldo' },
{ name: 'Vendas', icon: 'receipt', to: '/vendas' },
{ name: 'Account', icon: 'assignment', to: '/conta' },
{ name: 'Clients', icon: 'supervisor_account', to: '/clientes' },
{ name: 'More', [{ name: 'Sub-Item', icon: 'autorenew', to: '/sub-01' }] }
return r
}
<q-route-tab
v-for="(bTab, bTIndex) in getTabsMdl()"
:to="bTab.to"
:label="bTab.name"
:name="bTab.name"
:icon="bTab.icon"
:key="bTIndex"
no-caps
/>
In Quasar, you can define hierarchy of menus.
Please check this one.
https://github.com/quasarframework/quasar/blob/dev/docs/src/examples/QMenu/MenuInMenu.vue

How to create dynamic links based on an API request

I am completely new to both vue.js and Javascript. How do I dynamically create nav links from an Axios request?
I am wanting to follow what's being done in the item section which is currently static information, but i want to dynamically return links based on whats returned in the json request.
import * as types from '../../mutation-types'
import lazyLoading from './lazyLoading'
import charts from './charts'
// gathering items from API
const url = 'http://localhost:8080/items/'
data: {
items: []
},
mounted() {
axios.get(url).then(response => {
this.results = items.data
})
}
// Sidebar links are statically created here
const state = {
items: [
{
name: 'Dashboard',
path: '/dashboard',
meta: {
icon: 'fa-tachometer',
link: 'dashboard/index.vue'
},
component: lazyLoading('dashboard', true)
},
{
name: 'Axios',
path: '/axiosDemo',
meta: {
auth: true,
icon: 'fa-rocket',
link: 'axios/index.vue'
},
component: lazyLoading('axios', true)
},
charts,
]
}
const mutations = {
[types.EXPAND_MENU] (state, menuItem) {
if (menuItem.index > -1) {
if (state.items[menuItem.index] && state.items[menuItem.index].meta) {
state.items[menuItem.index].meta.expanded = menuItem.expanded
}
} else if (menuItem.item && 'expanded' in menuItem.item.meta) {
menuItem.item.meta.expanded = menuItem.expanded
}
}
}
export default {
state,
mutations
}
I think what I am wanting to do is something like this (python example):
items:
for i in items_payload:
{
name: i.name,
path: i.url,
meta: {
icon: 'fa-tachometer',
link: i.name+'/index.vue'
},
},
How do I best accomplish this in vue.js? Any help would be appreciated. Thanks.
If you are making the api request from a component, you can create a list of links like follows:
// for demo purposes, let's say links are returned as an array of objects
[
{
href: '/path/to/page1',
linkText: 'Page 1'
},
{
href: '/path/to/page2',
linkText: 'Page 2'
}
]
// MyComponent.vue
<template>
<div class="sidebar">
<ul>
<li v-for="(item, index) in items" :key="index">
<a :href="item.href">{{ item.linkText }}</a>
</li>
</ul>
</div>
</template>
export default {
data () {
return {
links: []
}
},
mounted() {
axios.get(url).then(response => {
this.links = items.data
})
}
}