Reputation: 461
I am using v-list-item-group to display a list of dynamic items (entities that can be created/deleted), of which can be selected to display more information about the selected item.
Up until this point, I have simply been using the model of v-list-item-group to determine which item has been selected.
<template>
<v-list>
<v-list-item-group v-model="listSelection">
<v-list-item v-for="(item, index) in items" :key="index">
</v-list-item>
</v-list-item-group>
</v-list>
</template>
<script>
export default {
props: {
value: Object
},
computed: {
items: function() {
return this.$store.state.items // Collection of entities from a server
},
listSelection: {
get: function() {
return this.items.indexOf(this.value)
},
set: function(newVal) {
this.$emit('input', this.items[newVal])
}
}
},
}
</script>
This approach works fine with the initial data set, as the first element in the list is the first object in items
, etc. However, if I add an entity in the middle, or remove something, or simply cause one of the items to shift to a different position in the list, the index to item position becomes invalid. Essentially if the list adds a new element, regardless of its position, its value (when selected in the group) is the next highest unused value. For example:
let fruits = ['apple', 'carrot']
<v-list-item>
for apple will have a value 0, and <v-list-item>
for carrot will have a value 1.
fruits.splice(1, 0, "banana")
<v-list-item>
for apple will have a value 0, <v-list-item>
for banana will have a value 2, and <v-list-item>
for carrot will have a value 1.
I've done a bunch of playing around with v-model and value in v-list-item-group
, but have not figured out how to avoid this problem. I would be fine with adding an @click
on my items, and having the items set a value
, rather than computing based on the list, but I would like the list selection to be maintained based on the value
.
As best as i've read, the documentation indicates that selection in lists should be handled using a v-list-item-group, but the component doesn't seem to support dynamic lists too well.
Upvotes: 17
Views: 10851
Reputation: 8623
There is a better to way to achieve it.
You just need to set the value of v-list-item
to :value="item"
should be ok.
See documentation of props value
for more detail:
The value used when a child of a v-list-item-group
.
https://v2.vuetifyjs.com/en/api/v-list-item/#props
<template>
<v-list>
<v-list-item-group v-model="listSelection">
<v-list-item v-for="(item, index) in items" :key="index" :value="item">
</v-list-item>
</v-list-item-group>
</v-list>
</template>
<script>
export default {
props: {
value: Object
},
data() {
return {
listSelection: []
}
}
computed: {
items: function() {
return this.$store.state.items; // Collection of entities from a server
},
},
}
</script>
Upvotes: 0
Reputation: 461
Upon additional inspection of the documentation, <v-list-item>
supports a value prop, allowing <v-list-item-group
to use a dictated value instead of the item index.
So the solution was to simply specify the items id as the value for each item, and then use the id as a means of managing the item group model.
<template>
<v-list>
<v-list-item-group v-model="listSelection">
<v-list-item v-for="(item, index) in items" :key="index" :value="item.id">
</v-list-item>
</v-list-item-group>
</v-list>
</template>
<script>
export default {
props: {
value: Object
},
computed: {
items: function() {
return this.$store.state.items; // Collection of entities from a server
},
listSelection: {
get: function() {
return this.value.id;
},
set: function(newVal) {
this.$emit('input', this.items.find(item => item.id === newVal));
}
}
},
}
</script>
Upvotes: 29