How can I bind a property only when a variable is set to true?
<template>
<v-list-tile :class="{[$color]: isItemSelected, [$primaryText]: isItemSelected}" :href="route">
<v-list-tile-action>
<v-icon :color="$primaryIcon">{{ icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template>
<script>
export default {
name: 'list-tile-text-icon',
props: ['icon', 'title', 'route'],
data: () => ({
isItemSelected: false
}),
created() {
this.isItemSelected = window.location.href === this.route;
}
}
</script>
On line 4 I need to bind in :color="$primaryColor" only when the isItemSelected variable is equal to true.
The values used in v-bind are JavaScript expressions, thus you can use the Conditional (ternary) operator:
<v-icon :color="isItemSelected ? $primaryIcon : null">
Note: I'm calling it v-bind because : is just a shorthand to v-bind. I.e. :color="" is the same as v-bind:color=""
Vue class and style binding doc
this is the offical document about vue class and style binding,
detail:
<v-list-title :class="{someClassYouDefine: isItemSelected}"> </v-list-title>
then write the style you want
<style>
.someClassYouDefine {
color: $primaryColor;
}
</style>
Related
i want to ask a question. I have many data that stored in vuex and i want to use v-for to loop the card with the array of the object keys. How do i get the data in mapGetters when the key is on the v-for loop?
I have tried the v-for with the key passing into curly braces. Code is below
<template>
<v-row>
<v-col cols="12" sm="6" md="6" lg="4" v-for="(topic, index) in topicList" :key="index">
<v-card class="mx-auto" max-width="400" outlined>
<v-list-item three-line>
<v-list-item-content>
<div class="text-overline">{{ topic.topic }}</div> // value topic from the map getters
<v-list-item-title class="text-h6 mb-1">
{{ topic.value }} // value from the map getters
</v-list-item-title>
<div class="text-overline">Value</div>
<v-list-item-subtitle>Timestamp</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-card>
</v-col>
</v-row>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
data: () => {
return {
topicList: [ //object keys array
"KL_LT1_PM_M6_ACTKWH",
"KL_LT1_PM_M6_ApparentPower",
],
};
},
computed: {
...mapGetters([
"KL_LT1_PM_M6_ACTKWH",
"KL_LT1_PM_M6_ApparentPower",
"KL_LT1_PM_M6_AVGCUR",
]),
},
};
</script>
Thankyou for the answer :)
import { mapGetters } from 'vuex'
const prefix = 'KL_LT1_PM_M6_'
const topicList = ['ACTKWH', 'ApparentPower'].map((topic) => `${prefix}${topic}`)
export default {
computed: {
...mapGetters([...topicList, `${prefix}AVGCUR`]),
topicList: () => topicList,
getTopic() {
return (topic) => this[topic] || {}
}
}
}
<v-col v-for="topic in topicList" :key="topic">
...
<div class="text-overline">{{ getTopic(topic).topic }}</div>
<v-list-item-title>{{ getTopic(topic).value }}</v-list-item-topic>
</v-col>
Most likely, your store could be greatly streamlined and, along with it, the components consuming it but, since you haven't shown it, I can't help you with that.
Note: if the above doesn't help you, there's likely a problem with your getters (try using them directly:
<pre
v-text="JSON.stringify({ KL_LT1_PM_M6_ACTKWH, KL_LT1_PM_M6_ApparentPower }, null, 2)"
/>
and see what you get).
If you need more help, consider adding a runnable minimal reproducible example, using codesandbox or similar.
Another note: moved topicList from data (e.g: data: () => ({ topicList })) to computed. There's no need for it to be reactive, it's a static list of strings. If you need it reactive (e.g: prefix or list are actually dynamic), move it back into data.
You can try using it as
{{ [topic].topic }} and {{ [topic].value }}
Hi I need to understand how to "pass" some $store values from settings module to header module, being the $store updated by settingsmodule
I have this app.vue module:
<template>
<v-app>
<router-view name="sidebar" />
<router-view name="header" :handleSettingsDrawer="handleSettingsDrawer" />
<v-main class="vue-content">
<v-fade-transition>
<router-view name="settings" />
</v-fade-transition>
</v-main>
<router-view name="footer" />
<app-settings-drawer
:handleDrawer="handleSettingsDrawer"
:drawer="settingsDrawer"
/>
</v-app>
</template>
in the <router-view name="header" /> there are a couple of v-menu to select currency and language:
<v-menu offset-y close-on-click>
<template v-slot:activator="{ on }">
<v-btn v-on="on" small fab class="mr-3">
<v-avatar size="30">
<v-img :src="currentLocaleImg"></v-img>
</v-avatar>
</v-btn>
</template>
<v-list dense class="langSel">
<v-list-item
v-for="(item, index) in langs"
:key="index"
#click="handleInternationalization(item.value,item.rtl)"
>
<v-list-item-avatar tile class="with-radius" size="25">
<v-img :src="item.img"></v-img>
</v-list-item-avatar>
<v-list-item-title>{{ item.text }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
in the script section I import the availableLanguages and availableCurrencies , I set them in data() where I also reference the user:
data() {
return {
items: [
{ icon: "settings", text: "Settings",link: "/settings" },
{ icon: "account_balance_wallet", text: "Account", link:"/tos" },
{ divider: true },
{ icon: "login", text: "Log In",link:"/auth/login" },
{ icon: "desktop_access_disabled", text: "Lock Screen",link:"/auth/lockscreen" },
{ icon: "exit_to_app", text: "Logout",link:"/auth/logout" },
],
langs: availableLocale,
currs: availableCurrency,
user: this.$store.state.userdata.user,
};
},
then, in computed: I have the 2 functions that should get the current value of curr and lang:
currentLocaleImg()
{
return this.langs.find((item) => item.value === this.$store.state.userdata.user.locale).img;
},
currentCurrencyImg() {
return this.currs.find((itemc) => itemc.value === this.$store.state.userdata.user.currency).img;
}
}
BUT the value of this.$store.state.userdata.user is updated firing the loadData() function mounted in the <router-view name="settings" /> module of App.vue
mounted(){
this.loadData();
},
methods:
{
async loadData(){
let jwt=sessionStorage.getItem('jwt');
try{
const res = await this.$http.post('/ajax/read_settings.php', {"jwt":jwt});
this.$store.dispatch("setUser", res.data.user);
this.$store.dispatch("setLocale", res.data.user.locale);
this.$store.dispatch("setCurrency", res.data.user.currency);
}
the problem is that header module does not have the value of this.$store.state.userdata.user.locale
(and .currency) and I get twice the following message:
vue.runtime.esm.js:1888 TypeError: Cannot read property 'img' of undefined
I do not know how to "pass" the data from one module to the other (or perhaps because the header is rendered before the settings module) and therefore the value of the currency and of the language are not known yet
What's wrong in this procedure?
How can I fix it?
There's a race condition in which you try to use data in the template that isn't loaded yet. But first, avoid setting store data directly into component data because the component data won't be updated when the store changes. Replace this:
user: this.$store.state.userdata.user
With a computed:
computed: {
user() {
return this.$store.state.userdata.user;
}
}
You can use v-if to conditionally render only when some data is available:
<v-img :src="currentLocaleImg" v-if="user"></v-img>
The currentLocaleImg computed will not even trigger until user has some data so you will avoid the error. Do the same for currentCurrencyImg if necessary.
I use vue-select in my Vue app. I created a component as a wrapper for v-select. To return only a specific column of the options array, I use the :reduce prop of vue-select.
<template>
<span>
<label v-if="title">{{title}}</label>
<v-select
:options="options"
:label="label"
:placeholder="placeholderText"
:close-on-select="closeOnSelectValue"
:disabled="isDisabled"
:multiple="multiple"
:value="value"
#input="handleInput($event)"
:loading="isLoading"
:reduce="option=> option.val"
></v-select>
</span>
This code works, but I would like to have the static val string to be the dynamic prop returnKey. This would be passed to the component as a prop.
props: {
returnKey: {
type: String,
default: null,
},
}
What syntax should I use to make a combination of the 'option' string and the dynamic value of 'returnKey' in the function passed to :reduce to get this working?
You can use the bracket notation and do option => option[returnKey].
And as what Richard has suggested, in order to avoid runtime error you might want to provide some kind of fallback, or enforce that returnKey must be a required prop.
You can try something like this
<template>
<span>
<label v-if="title">{{title}}</label>
<v-select
:options="options"
:label="label"
:placeholder="placeholderText"
:close-on-select="closeOnSelectValue"
:disabled="isDisabled"
:multiple="multiple"
:value="value"
#input="handleInput($event)"
:loading="isLoading"
:reduce="reduceKey"
></v-select>
</span>
</template>
<script>
export default
{
props: {
returnKey: {
type: String,
default: null,
},
},
methods:
{
reduceKey(option)
{
return option[this.returnKey] || option;
}
}
}
I'm trying to create buttons dynamically whose names are fetched from keys of an Object. And I need to pass the corresponding value to the method to get my code work. How do you do both of these tasks?
<template>
<v-app>
<router-view></router-view>
<v-app-bar app dense id="abc" dark>
<v-icon>note_add</v-icon>
<v-toolbar-title>Title</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn
v-for="(value, key) in button_redirect_to"
:key="key"
#click="render_comp()"
>{{ key }}</v-btn>
<v-btn depressed fab small>
<v-icon>notifications</v-icon>
</v-btn>
</v-app-bar>
</v-app>
</template>
<script>
export default {
name: "Navbar",
data() {
return {
button_redirect_to: {
Projects: "/projects",
Requests: "/requests",
Reports: "/reports",
Resources: "/resources",
temp: "/temp"
},
pers_actions: ["Profile", "LogOut"]
};
},
methods: {
render_comp() {
this.$router.push();
}
}
};
</script>
In your for-loop, value is the route and key is the button label. Just pass the route (value) as an argument:
#click="render_comp(value)"
methods: {
render_comp(to) {
this.$router.push(to);
}
}
Pass the value variable from the for loop (which in the first case will be "/projects") as an argument of #click="render_comp(value)" handler so it can be used inside the function.
<v-btn
v-for="(value, key) in button_redirect_to"
:key="key"
#click="render_comp(value)"
>
{{ key }}
</v-btn>
render_comp will then have access to it so it can be passed into this.$router.push(), making the function this.$router.push("/projects").
methods: {
render_comp(value) {
this.$router.push(value);
}
}
Hope this helps.
I have a button in my view
<v-menu offset-y>
<v-btn>
Action Items
</v-btn>
<v-list>
<v-list-tile
v-for="(item, index) in items"
:key="index"
:disabled="item.disabled"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-data-table
v-model="selected">
my data looks like
<script>
export default {
data: () => ({
selected: [],
items: [
{ title: 'Delete',disabled:false},
],
...
i am trying to enable or disable the v-list-tile based on whether the selected array has any values.
i tried something like:
items: [
{ title: 'Delete',disabled:this.selected.length=0},
],
but it gives me the following error:
[Vue warn]: Property or method "selected" is not defined on the instance but referenced during render.
please help me to resolve this issue.
I would say rather than have a disabled property on your model, you can have it as a computed property like so:
computed: {
disabled() {
return this.selected.length < 1; // or === 0
}
}
Then use the disabled property in your component.
<v-list-tile v-for="(item, index) in items"
:key="index"
:disabled="disabled">
<v-list-tile-title>
{{ item.title }}
</v-list-tile-title>
</v-list-tile>
PS: that props is passed into your v-list-tile as disabled property of that element. I am not sure if a custom component will be disabled (otherwise you know you'll use it on a real html element)