On a button click based on value matching, I am trying populate an array with objects that i visualise in another components, here's how i do it:
This is the method that commits the mutation #click:
modifySelectedLimitCardStatus() {
const payload = [
this.editedLimitCard.id,
(this.editedLimitCard.limit_card_selected_status = true)
];
this.$store.commit("selectLimitCard", payload);
}
The state & mutation:
selectedLimitCard: [],
selectLimitCard: (state, payload) => {
state.limitCards.forEach(limitCard => {
if (
limitCard.id === payload[0] &&
limitCard.limit_card_selected_status !== payload[1]
) {
state.selectedLimitCard.push(limitCard);
console.log(state.selectedLimitCard);
}
});
}
And finally, the getter:
getSelectedLimitCard: state => {
return state.selectedLimitCard;
}
As you can see in the code, i log the state in the mutation and it's populated,
[{…}, __ob__: Observer]
however, in the component that is supposed to visualise the getter
<v-list :items="getSelectedLimitCard">
<v-list-tile>
<v-list-tile-content>№</v-list-tile-content>
<v-list-tile-content class="align-end">
{{ getSelectedLimitCard.limit_card_number }}
</v-list-tile-content>
</v-list-tile>
</v-list>
i get nothing.
Everything was working fine before i introduced the .push() way ot populating the array.
Can someone help me out & point out what i'm doing wrong?
Thanks in advance!
<v-list>
<v-list-tile v-for="card in getSelectedLimitCard" :key="card.limit_card_number">
<v-list-tile-content>№</v-list-tile-content>
<v-list-tile-content class="align-end">
{{ card.limit_card_number }}
</v-list-tile-content>
</v-list-tile>
</v-list>
Related
I made a component like treeview to show data like this:
[how my treeview shows][1]
<ul v-for="(build, index) in buildingList" :key="index">
<v-list-item>
<v-list-item-icon>
<v-icon v-show="build.apartments.length || build.guilds.length"
#click="showSub(index)">
{{ showAll ? ' mdi-chevron-up' : ' mdi-chevron-down' }}
</v-icon>
</v-list-item-icon>
</v-list-item>
<v-list-item-group v-show="currentIndex === index">
<li v-for="(apart) in build.apartments"
:key="apart.folderEid"
#load="getApartCode(apart.renewalCode)">
<v-list-item>
{{apart.title}}
</v-list-item>
</li>
<li v-for="(guild) in build.guilds"
:key="guild.folderEid">
<v-list-item>
{{guild.title}}
</v-list-item>
</li>
</v-list-item-group>
</ul>
when I want to open one of the list group items, I said get the index and open it. but now, I wanna make it show all the indexes when I open the page. the codes in data and methods:
data => currentIndex: -1,showAll: false,
in Methods:
methods: {
showSub(index) {
this.showAll = !this.showAll
this.currentIndex = this.currentIndex === index ? -1 : index
console.log(index, this.currentIndex)
},
async propertyTreeGet() {
this.loading = true
// this.showAll = true
// if ()
await this.$store.dispatch("axiosGet", {
url: `folder/api/properties/tree/${this.id}`
}).then(response => {
this.propertyList = response.data.data
this.loading = false
this.propertyTree.push(response.data.data)
this.propertyList.buildings.filter(build => {
this.buildingList.push(build)
return build.renewalCode = this.buildRenewal
})
this.getData()
})
},
}
I couldn't use the Vuetify treeview because in API we didn't have children but arrays of building, apartment, and guid inside the main array. Can anyone please give me a hint or a simpler example?
[1]: https://i.stack.imgur.com/0MmzE.png
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 }}
selected value get disappeared in the v-autocomplete. I've used vuetify v-autocomplete component for this. once I select a value and then when I click another component or when I continue the process that selected value get disappeared.
<v-autocomplete
:search-input.sync="search"
append-icon="mdi-chevron-down"
v-model="selectedCode"
item-text="name"
item-value="code"
class="my-input"
solo
:items="items"
label="select"
>
<template v-slot:no-data>
<v-list-item>
<v-list-item-content>
<v-list-item-title> Type to filter</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-autocomplete>
data() {
return {
search: null
};
},
watch: {
search(val) {
this.festchData({
search: val
});
}
},
in this scenario, I was able to solve this issue by checking a couple of values within the watch().
<v-autocomplete
return-object
:loading="isloading"
clearable
append-icon="mdi-chevron-down"
v-model.lazy="trans.code"
solo
:search-input.sync="search"
class="transaction-input"
:items="merchantList"
:disabled="displayText
"
item-text="name"
item-value="code"
:label="displayText"
:rules="[rules.required]"
>
</v-autocomplete>
watch: {
search(val) {
// if the search value is empty
if (val === undefined || val === null || val.length === 0) {
// make dataList empty
this.makeDataListEmpty();
this.isloading = false;
return;
}
// Items have already been loaded
if (this.dataList.length > 0) return;
// Items have already been requested
if (this.isloading) return;
this.isloading = true;
Promise.all([this.fetchData(val)]).finally(() => {
this.isloading = false;
});
}
},
the watch is listening to the actions and it gets triggered every time action gets executed. so we need to check whether we have to filter the data at a particular time or not.
I have Vue component that renders a list of Vuetify cards:
<restaurant-item
v-for="card in userRestaurantCards"
:key="card['.key']"
:card="card"
>
</restaurant-item>
The card displays info obtained from props, Vuex, as well as info defined in the restaurant-item card itself:
<v-card>
<v-img
class="white--text"
height="200px"
:src="photo"
>
<v-container fill-height fluid class="card-edit">
<v-layout fill-height>
<v-flex xs12 align-end flexbox>
<v-menu bottom right>
<v-btn slot="activator" dark icon>
<v-icon>more_vert</v-icon>
</v-btn>
<v-list>
<edit-restaurant-dialog :card="card" :previousComment="comment"></edit-restaurant-dialog>
<v-list-tile >
<v-list-tile-title>Delete</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</v-flex>
</v-layout>
</v-container>
</v-img>
<v-card-title>
<div>
<span class="grey--text">Friends rating: {{ card.rating }}</span><br>
<h3>{{ card.name }}</h3><br>
<span>{{ card.location }}</span>
</div>
</v-card-title>
<v-card-actions>
<v-btn flat color="purple">Comments</v-btn>
<v-spacer></v-spacer>
<v-btn icon #click="show = !show">
<v-icon>{{ show ? 'keyboard_arrow_down' : 'keyboard_arrow_up' }}</v-icon>
</v-btn>
</v-card-actions>
<v-slide-y-transition>
<v-card-text v-show="show">
<div> {{ comment.content }} </div>
</v-card-text>
</v-slide-y-transition>
</v-card>
The script is:
import { find, isEmpty } from 'lodash-es'
import { mapGetters } from 'vuex'
import EditRestaurantDialog from '#/components/dashboard/EditRestaurantDialog'
export default {
name: 'restaurant-item',
components: {
EditRestaurantDialog
},
props: {
card: Object
},
data() {
return {
show: false,
name: this.card.name,
location: this.card.location,
rating: this.card.rating,
link: this.card.link,
photo: this.getPhotoUrl()
}
},
computed: {
comment() {
// Grab the content of the comment that the current user wrote for the current restaurant
if (isEmpty(this.card.comments)) {
return { content: 'You have no opinions of this place so far' }
} else {
const userComment = find(this.card.comments, o => o.uid === this.currentUser)
return userComment
}
},
...mapGetters(['currentUser'])
},
methods: {
getPhotoUrl() {
const cardsDefault = find(this.card.photos, o => o.default).url
if (isEmpty(cardsDefault)) {
return 'https://via.placeholder.com/500x200.png?text=No+pics+here+...yet!'
} else {
return cardsDefault
}
}
}
}
Here is the kicker: when I have 2 objects in the data, the first card component renders correctly... while the second doesn't have any of the methods or data defined right there in the script.
Here's a link to a screenshot of the Vue Devtools inspecting the first card:
https://drive.google.com/file/d/1LL4GQEj0S_CJv55KRgJPHsCmvh8X3UWP/view?usp=sharing
Here's a link of the second card:
https://drive.google.com/open?id=13MdfmUIMHCB_xy3syeKz6-Bt9R2Yy4Xe
Notice how the second one has no Data except for the route?
Also, note that both components loaded props, vuex bindings and computed properties just as expected. Only the Data is empty on the second one...
I've been scratching my head for a while over this. Any ideas would be more than welcome.
I got it to work after I moved the method getPhotoUrl method to a computed property:
computed: {
comment() {
// Grab the content of the comment that the current user wrote for the current restaurant
if (isEmpty(this.card.comments)) {
return { content: 'You have no opinions of this place so far' }
} else {
const userComment = find(this.card.comments, o => o.uid === this.currentUser)
return userComment
}
},
photoUrl() {
const cardsDefault = find(this.card.photos, o => o.default)
if (isEmpty(cardsDefault)) {
return 'https://via.placeholder.com/500x200.png?text=No+pics+here+...yet!'
} else {
return cardsDefault.url
}
},
...mapGetters(['currentUser'])
}
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)