I've got a doughnut chart being displayed using vue-chartjs and am supplying color schemes via chartjs-plugin-colorschemes.
I'm working on the ability for the user to switch out color schemes and persist their chosen scheme to the db, however I've run into an odd issue. When adding a colors array to the options that are being supplied to the Vuetify select, it breaks the chart from updating to the new color scheme. I've narrowed it down to this specifically, because if I remove the colors array from options, it correctly updates the chart (however then I'm not able to display the colors like I'm trying to do in the select dropdown).
Why would adding properties to the Vuetify select break this functionality? Is it because they're being dynamically generated?
**ParentComponent.vue:**lang-vue
<template>
<div
class="chart-wrapper">
<child-graph
v-resize="onResize"
:chart-data="chartData"
:is-mobile="isMobile"
:styles="graphStyles"
:theme="localTheme" />
</div>
<pack-theme-modal
v-model="themeModalOpen"
:theme="localTheme"
#handle-update="handleUpdateTheme" />
</template>
<script>
export default {
data () {
localTheme: '',
themeModalOpen: false
},
methods: {
handleUpdateTheme (theme) {
this.localTheme = theme;
this.themeModalOpen = false;
}
}
}
</script>
ChildGraph.vue:
<script>
import { Doughnut, mixins } from 'vue-chartjs';
import Chart from 'chart.js';
import 'chartjs-plugin-colorschemes';
const { reactiveProp } = mixins;
export default {
extends: Doughnut,
mixins: [reactiveProp],
props: {
theme: {
type: String,
default: ''
}
},
data () {
const vm = this;
return {
options: {
cutoutPercentage: 75,
legend: {
display: true,
position: 'right'
},
plugins: {
colorschemes: {
scheme: this.theme
}
},
responsive: true,
maintainAspectRatio: false,
tooltips: {
enabled: false
},
}
};
},
mounted () {
this.renderChart(this.chartData, this.options);
},
watch: {
theme (newVal, oldVal) {
console.log({ newVal });
const chart = this.$data._chart;
chart.options.plugins.colorschemes.scheme = newVal;
chart.update();
}
}
};
</script>
ThemeModal.vue:
<template>
<v-dialog
v-model="show"
max-width="750">
<v-card>
<v-card-title>
Choose a New Chart Color Theme
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12">
<v-select
v-model="localTheme"
color="primary"
dense
item-text="text"
item-value="value"
:items="options"
label="Theme Options"
outlined>
<template #selection="{ item }">
<p class="mb-0 mr-4 text-body-1">
{{ item.text }}
</p>
<color-swatch :colors="item.colors" />
</template>
<template #item="{ item, attrs, on }">
<v-list-item
v-bind="attrs"
v-on="on">
<v-list-item-content>
<v-list-item-title>
<span class="mr-4">{{ item.text }}</span>
<color-swatch :colors="item.colors" />
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-select>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions class="justify-space-between">
<v-btn
class="grey7--text"
:ripple="false"
text
#click="closeModal">
Cancel
</v-btn>
<v-btn
color="primary"
depressed
:ripple="false"
#click="handleUpdate">
<span>Update Theme</span>
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import 'chartjs-plugin-colorschemes/src/plugins/plugin.colorschemes';
import { Blue6, BlueGreen6, Breeze6, Celestial6, Circuit6, Damask6, Depth6, Flow6, Forte6, Genesis6, IonBoardroom6, Kilter6 } from 'chartjs-plugin-colorschemes/src/colorschemes/colorschemes.office';
import { Tableau10, ColorBlind10, JewelBright9, HueCircle19 } from 'chartjs-plugin-colorschemes/src/colorschemes/colorschemes.tableau';
import ColorSwatch from '~/components/ColorSwatch.vue';
export default {
props: {
theme: {
type: String,
default: ''
},
value: {
type: Boolean,
default: false
}
},
data () {
return {
localTheme: this.theme || 'tableau.Tableau10',
options: [
// COMMENTED OUT OPTIONS WORK, BUT DON'T DISPLAY COLOR SWATCH
// { text: 'Theme 1', value: 'office.Blue6' },
// { text: 'Theme 2', value: 'office.BlueGreen6' },
// { text: 'Theme 3', value: 'office.Breeze6' },
// { text: 'Theme 4', value: 'office.Celestial6' },
// { text: 'Theme 5', value: 'office.Circuit6' },
// { text: 'Theme 6', value: 'office.Damask6' },
// { text: 'Theme 7', value: 'office.Depth6' },
// { text: 'Theme 8', value: 'office.Flow6' },
// { text: 'Theme 9', value: 'office.Forte6' },
// { text: 'Theme 10', value: 'office.Genesis6' },
// { text: 'Theme 11', value: 'office.IonBoardroom6' },
// { text: 'Theme 12', value: 'office.Kilter6' },
// { text: 'Theme 13', value: 'tableau.Tableau10' },
// { text: 'Theme 14', value: 'tableau.ColorBlind10' },
// { text: 'Theme 15', value: 'tableau.JewelBright9' },
// { text: 'Theme 16', value: 'tableau.HueCircle19' }
// COMMMENTED IN OPTIONS SHOW COLOR SWATCH BUT DON'T UPDATE GRAPH
{ text: 'Theme 1', value: 'office.Blue6', colors: Blue6.map(color => color) },
{ text: 'Theme 2', value: 'office.BlueGreen6', colors: BlueGreen6.map(color => color) },
{ text: 'Theme 3', value: 'office.Breeze6', colors: Breeze6.map(color => color) },
{ text: 'Theme 4', value: 'office.Celestial6', colors: Celestial6.map(color => color) },
{ text: 'Theme 5', value: 'office.Circuit6', colors: Circuit6.map(color => color) },
{ text: 'Theme 6', value: 'office.Damask6', colors: Damask6.map(color => color) },
{ text: 'Theme 7', value: 'office.Depth6', colors: Depth6.map(color => color) },
{ text: 'Theme 8', value: 'office.Flow6', colors: Flow6.map(color => color) },
{ text: 'Theme 9', value: 'office.Forte6', colors: Forte6.map(color => color) },
{ text: 'Theme 10', value: 'office.Genesis6', colors: Genesis6.map(color => color) },
{ text: 'Theme 11', value: 'office.IonBoardroom6', colors: IonBoardroom6.map(color => color) },
{ text: 'Theme 12', value: 'office.Kilter6', colors: Kilter6.map(color => color) },
{ text: 'Theme 13', value: 'tableau.Tableau10', colors: Tableau10.map(color => color) },
{ text: 'Theme 14', value: 'tableau.ColorBlind10', colors: ColorBlind10.map(color => color) },
{ text: 'Theme 15', value: 'tableau.JewelBright9', colors: JewelBright9.map(color => color) },
{ text: 'Theme 16', value: 'tableau.HueCircle19', colors: HueCircle19.map(color => color) }
]
};
},
computed: {
show: {
get () {
return this.value;
},
set (value) {
this.$emit('input', value);
}
}
},
methods: {
closeModal () {
this.show = false;
},
handleUpdate () {
this.$emit('handle-update', this.localTheme);
}
},
watch: {
theme (val) {
this.localTheme = val;
}
},
components: {
ColorSwatch
}
};
</script>
On a Hail Mary attempt, I found something in the chartjs-plugin-colorschemes docs that mentioned setting override: true within the color schemes object on data. Adding that fixed it somehow!
plugins: {
colorschemes: {
scheme: this.theme,
override: true
}
},
Related
I'm new in Vuejs and I'm currently working with composition API, I have a nav component where I have an Array called tabs as you can see that array is static.
So I want to do this dynamic and send that props from another component. I read about that but I do not understand at all.
Supossely I can change the array of my component with a model like:
const tabs<MyModel>
And then I can send it from the other component, but I'm lost
Nav component
<template>
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<select
id="tabs"
name="tabs"
class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
>
<option v-for="tab in tabs" :key="tab.name" :selected="tab.current">
{{ tab.name }}
</option>
</select>
</div>
<div class="hidden sm:block">
<nav class="flex items-center space-x-4">
<a
v-for="tab in tabs"
:key="tab.name"
:href="tab.href"
:class="[
tab.current
? 'bg-purple-70 q0 text-white'
: 'text-purple-700 hover:text-gray-700',
'px-12 py-2 rounded-full font-bold text-xl',
]"
#click="changeTab(tab)"
>
{{ tab.name }}
</a>
</nav>
</div>
<div class="hidden sm:block">
<div
v-for="tab in tabs"
:key="tab.name"
:href="tab.href"
class="px-12 flex justify-center"
:class="[tab.current || 'hidden']"
#click="changeTab(tab)"
>
{{ tab.id }} - {{ tab.name }} - {{ tab.href }} - {{ tab.title }}
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, computed } from '#vue/composition-api'
import i18n from '#/setup/i18n'
export default defineComponent({
name: 'ProgramModal',
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
])
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
tabs,
changeTab,
ariaLabel,
}
},
})
</script>
The component where I want to send parameters:
<template>
<ProgramModal />
</template>
<script lang="ts">
import ProgramModal from '#/components/ProgramModal.vue'
import { defineComponent, ref } from '#vue/composition-api'
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
const isModalOpen = ref(true)
const showModal = () => {
isModalOpen.value = true
}
return {
isModalOpen,
showModal,
}
},
})
</script>
How can I change this logic to receive different values? Regards
Two schemes, props or composables:
1. Use props:
You can create tabs in Home component and pass to ProgramModel:
<template>
<ProgramModal :tabs="tabs" />
</template>
<script lang="ts">
import ProgramModal from '#/components/ProgramModal.vue'
import { defineComponent, ref } from '#vue/composition-api'
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
// ...
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
])
return { tabs }
},
})
</script>
Then, define a prop in ProgramModal component:
export default defineComponent({
name: 'ProgramModal',
props: {
tabs: Array as PropType<Array<Tab>>
},
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
tabs,
changeTab,
ariaLabel,
}
},
})
2. Use composables (Vue3 recommend)
You can define a file named useTab:
// useTab.js
const tabs = ref([
{
id: 1,
title: 'test title one',
imageSrc: '/programs/test1.png',
content: '',
name: 'LOREM',
href: '#test1',
current: true,
},
{
id: 2,
title: 'test title two',
imageSrc: '/programs/test2.png',
content: '',
name: 'IPSUM',
href: '#test2',
current: false,
},
{
id: 3,
title: 'test title three',
imageSrc: '/programs/test3.png',
content: '',
name: 'PDF',
href: '#test3',
current: false,
},
]);
export default function (
const changeTab = (selectedTab: { id: number }) => {
tabs.value.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return { tabs, changeTab }
)
Then, you can use it anywhere.
// Home.vue
export default defineComponent({
name: 'Home',
components: {
ProgramModal,
},
setup() {
// ...
// By this way, you can change tab in Home or anywhere you want.
const { changeTab } = useTab();
return { }
},
})
// ProgramModal.vue
export default defineComponent({
name: 'ProgramModal',
setup() {
const ariaLabel = computed(() => i18n.t('share') as string)
const { tabs, changeTab } = useTab();
return {
tabs,
changeTab,
ariaLabel,
}
},
})
By the way, method 2 is the real composition api. :)
I got some problem with Vuetify treeview component. My goal is:
When I select some treeview's element and press expand /collapse button I want to see all children for this element, and then when I press the button once again I want to collapse all selected element.
Here's my code:
<template>
<v-container fluid>
<v-btn justify-center #click="expandCollapse"> Expand or collapse </v-btn>
<v-treeview
class="ml-4"
v-model="tree"
:open="items"
:items="items"
activatable
item-key="name"
>
<template slot="prepend" slot-scope="{ item }">
<v-list-tile-avatar
size="30"
style="min-width: 40px;"
tile
>
<img :src="imageType(item.type)" alt=""/>
</v-list-tile-avatar>
</template>
</v-treeview>
</v-container>
</template>
<script>
export default {
data: () => ({
items: [
{
name: 'Factory A',
type: 'board',
children: [
{
name: 'Line 1',
children: [{
name: 'Machine ABC',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 2',
children: [{
name: 'Machine ABC 02',
children: [{
name: 'Part A',
type: 'part'
},
{
name: 'Part B',
type: 'part'
},
{
name: 'Part C',
type: 'part'
},
{
name: 'Part D',
type: 'part'
}
],
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 3',
children: [{
name: 'Machine ABC 03',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 4',
children: [{
name: 'Machine ABC 04',
type: 'machine'
}],
type: 'board'
}
]
}
]
}),
methods: {
imageType (type) {
switch (type) {
case 'board':
return require('#/assets/images/board.svg')
case 'machine':
return require('#/assets/images/machine.svg')
case 'part':
return require('#/assets/images/part.svg')
}
},
// ADDED
bfs: function (tree, key, collection) {
if (!tree[key] || tree[key].length === 0) return
for (var i = 0; i < tree[key].length; i++) {
var child = tree[key][i]
collection.push(child)
this.bfs(child, key, collection)
}
},
expandCollapse (item) {
const childs = []
const selectedIDs = []
childs.push(item)
this.bfs(item, 'children', childs)
}
}
}
</script>
Ok, I got the solution. I just added two if-statements to function.
if (this.open.indexOf(selectedIDs[0]) === -1) {
this.open = this.open.concat(childs.map(node => node.id))
} else {
this.open = this.open.filter((item) => !selectedIDs.includes(item))
}
Use the open and active event listeners to update the open/closed items.
To get the active items use the update:active event.
To get the open items use the update:open event.
on expandCollapse use the active items and the open items to determine whether to open or close, and then update the open to reflect the change. This part is just iterating through the items and running a comparing to active and open
I have an issue with all my checkboxes always being true.
I've tried using the "false-value" attribute, but to no help.
I also have a default input checkbox, which is functioning properly.
export default {
data() {
return {
straps: [],
checkedColors: [],
checkedSkins: [],
checkedTypes: [],
filterings: [{
title: "Farver",
filters: [{
title: "Grøn",
value: "grøn",
model: "checkedColors"
},
{
title: "Rød",
value: "rød",
model: "checkedColors"
},
{
title: "Gul",
value: "yellow",
model: "checkedColors"
},
{
title: "Lilla",
value: "lilla",
model: "checkedColors"
},
{
title: "Blå",
value: "blå",
model: "checkedColors"
},
{
title: "Grå",
value: "grå",
model: "checkedColors"
},
{
title: "Sort",
value: "sort",
model: "checkedColors"
},
{
title: "Hvid",
value: "hvid",
model: "checkedColors"
},
{
title: "Brun",
value: "brun",
model: "checkedColors"
}
]
},
{
title: "Materialer",
filters: [{
title: "Alligator",
value: "alligator",
model: "checkedSkins"
},
{
title: "Struds",
value: "ostridge",
model: "checkedSkins"
},
{
title: "Teju firben",
value: "teju",
model: "checkedSkins"
},
{
title: "Haj",
value: "shark",
model: "checkedSkins"
}
]
},
{
title: "Remme til",
filters: [{
title: "Universal",
value: "universal",
model: "checkedTypes"
},
{
title: "Audemars Piguet",
value: "ap",
model: "checkedTypes"
},
{
title: "Jaeger LeCoultre",
value: "jlc",
model: "checkedTypes"
},
{
title: "Rolex",
value: "rolex",
model: "checkedTypes"
}
]
}
]
};
},
computed: {
filteredStraps() {
var straps = this.straps;
if (this.search !== null) {
var straps = this.searchItems.filter(strap => {
if (!this.search) return this.searchItems;
return (
strap.title.toLowerCase().includes(this.search.toLowerCase()) ||
strap.skin.toLowerCase().includes(this.search.toLowerCase()) ||
strap.type.toLowerCase().includes(this.search.toLowerCase())
);
});
}
if (this.checkedSkins.length > 0) {
straps = straps.filter(strap => {
return this.checkedSkins.includes(strap.skin.toLowerCase());
});
}
if (this.checkedTypes.length > 0) {
straps = straps.filter(strap => {
return this.checkedTypes.includes(strap.type.toLowerCase());
});
}
if (this.sort == "newest") {
return straps.sort((a, b) => new Date(a.date) - new Date(b.date));
}
if (this.sort == "priceasc") {
return straps.sort((a, b) => a.price > b.price);
}
if (this.sort == "pricedesc") {
return straps.sort((a, b) => a.price < b.price);
} else {
return straps;
}
},
getStraps() {
db.collection("straps")
.get()
.then(querySnapshot => {
const straps = [];
querySnapshot.forEach(doc => {
const data = {
id: doc.id,
title:
doc
.data()
.type.charAt(0)
.toUpperCase() +
doc.data().type.slice(1) +
" RIOS1931 " +
doc
.data()
.title.charAt(0)
.toUpperCase() +
doc.data().title.slice(1) +
" Urrem i " +
doc
.data()
.skin.charAt(0)
.toUpperCase() +
doc.data().skin.slice(1),
price: doc.data().price,
skin: doc.data().skin,
type: doc.data().type,
imgs: doc.data().imgs[0].url,
colors: doc.data().colors,
date: doc
.data()
.date.toString()
.slice(0, 15)
};
straps.push(data);
});
this.straps = straps;
});
},
}
<v-layout>
<v-flex sm3 md2 class="hidden-xs-only text-xs-left">
<p class="pl-4"><strong>Sortering</strong></p>
<v-expansion-panel class="elevation-0">
<v-expansion-panel-content v-for="filtering in filterings" :key="filtering.title">
<div slot="header">{{filtering.title | capitalize}}</div>
<v-card>
<v-card-text>
<v-list>
<input type="checkbox" value="alligator" v-model="checkedSkins">
<label for="checker"></label>
<v-list-tile v-for="filter in filtering.filters" :key="filter.value">
<v-list-tile-content>
<v-checkbox :input-value="filter.value" :label="filter.title" v-model="filter.model" color="primary"></v-checkbox>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-card-text>
</v-card>
</v-expansion-panel-content>
<v-expansion-panel-content>
<div slot="header">Pris</div>
<v-card>
<v-card-text>
<v-layout>
<v-flex px-2>
<v-range-slider :min="slider[0]" :max="slider[1]" v-model="slider" thumb-label="always"></v-range-slider>
</v-flex>
</v-layout>
<v-layout>
<v-flex xs6 pr-2>
<v-text-field label="Fra pris" v-model="slider[0]" class="mt-0" hide-details single-line type="number"></v-text-field>
</v-flex>
<v-flex xs6 pl-2>
<v-text-field label="Til pris" v-model="slider[1]" class="mt-0" hide-details single-line type="number"></v-text-field>
</v-flex>
</v-layout>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-flex>
</v-layout>
As mentioned the default input works as intended, but the vuetify checkboxes are all returning true for some reason, and they won't work, even though they have the same attribute values in the front-end.
If you want to store checked objects as strings from filter.value property so you have 2 issues in your code(second one is related to your question):
You have incorrect value in your v-model directive. You bind filter.model variable to v-model not its stored array name, to fix this you should pass to v-model something like this $data[filter.model] to bind array from data as model dynamically.
You use input-value binding incorrectly. input-value is related to v-model value(see v-checkbox source code, it's overriding of default model), you don't need to change this value. So you need to pass filter.value to value attribute instead.
Result:
<v-checkbox :value="filter.value" :label="filter.title" v-model="$data[filter.model]" color="primary"></v-checkbox>
Does anyone know how to actually display the text value from multiple dependent select fields?
I need option 1 to list a set of parent options. When an Option 1 is selected, it will determine the values available in Option 2 select field.
I then want the text value associated with the selected option to be displayed below the select field.
<template>
<div>
<panel class="main-content">
<div>
<b-form-select v-model="selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ selected }}</strong></div>
</div>
<div>
<b-form-select v-model="selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ selected }}</strong></div>
</div>
</panel>
</div>
</template>
<script>
export default {
data () {
return {
selected: null,
options: [
{ value: null, name: 'opt', text: 'Select One' },
{ value: 'option1', name: 'mys', text: 'Carbohydrates' },
{ value: 'option2', name: 'hkong', text: 'Fibre' },
{ value: 'option3', name: 'spore', text: 'Fat' }
]
}
}
}
</script>
Kindly assist since it's something new for me in VueJs.
This is working in VueJS (tested). I was a little off about how the b-form-select element works, but this will give you the results you need.
If you are building the options manually, maybe just make a JSON file or a Component that returns these sets of options and subOptions and import it rather than putting all the options into your template (Cleaner Code).
<script>
export default {
data () {
return {
option1Selected: null,
option2Selected: null,
options: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option1',
name: 'mys',
text:'Carbohydrates',
},
{
value: 'option2',
name: 'hkong',
text: 'Fibre',
},
{
value: 'option3',
name: 'spore',
text: 'Fat',
},
],
subOptions: {
option1: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option1-1',
name: 'o1-1Name',
text: 'Option 1-1 Text',
},
{
value: 'option1-2',
name: 'o1-2Name',
text: 'Option 1-2 Text',
},
{
value: 'option1-3',
name: 'o1-3Name',
text: 'Option 1-3 Text',
},
],
option2: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option2-1',
name: 'o2-1Name',
text: 'Option 2-1 Text',
},
{
value: 'option2-2',
name: 'o2-2Name',
text: 'Option 2-2 Text',
},
{
value: 'option2-3',
name: 'o2-3Name',
text: 'Option 2-3 Text',
},
],
option3: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option3-1',
name: 'o3-1Name',
text: 'Option 3-1 Text',
},
{
value: 'option3-2',
name: 'o3-2Name',
text: 'Option 3-2 Text',
},
{
value: 'option3-3',
name: 'o3-3Name',
text: 'Option 3-3 Text',
},
],
}
}
},
computed: {
option1text () {
for (const key in this.options) {
if (this.options[key].value === this.option1Selected) {
return this.options[key].text;
}
}
},
option2text () {
if (this.option1Selected != null) {
for (const key in this.subOptions[this.option1Selected]) {
if (this.subOptions[this.option1Selected][key].value === this.option2Selected) {
return this.subOptions[this.option1Selected][key].text;
}
}
}
}
},
}
</script>
<template>
<div>
<panel class="main-content">
<div>
<b-form-select v-model="option1Selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ option1text }}</strong></div>
</div>
<div v-if="option1Selected != null">
<b-form-select v-model="option2Selected" :options="subOptions[option1Selected]" class="mb-3" />
<div>Selected: <strong>{{ option2text }}</strong></div>
</div>
</panel>
</div>
</template>
Note I have updated code to properly reflect exactly what you were asking for in the question: the Text value of the option.
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>