When the data array changes order, the state of panels that are open does not follow their data positions.
<div id="app">
<v-app id="inspire">
<div>
<div class="text-center d-flex pb-4">
<v-btn @click="changeOrder">Change order</v-btn>
<v-btn @click="removeItem">Remove item</v-btn>
</div>
<v-expansion-panels
v-model="panel"
multiple
>
<v-expansion-panel
v-for="(item, i) in items">
<v-expansion-panel-header>{{ item.name }}</v-expansion-panel-header>
<v-expansion-panel-content>
Lorem ipsum dolor sit amet.
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</div>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
panel: [],
items: [
{ id:1, name: 'James', },
{ id:2, name: 'Bernt', },
{ id:3, name: 'Julie', },
{ id:4, name: 'Veronica', },
],
}
},
methods: {
changeOrder () {
this.items = this.items.reverse();
},
removeItem () {
this.items.splice(0, 1);
},
},
})
https://codepen.io/Agint/pen/GRpmBxE
In the demo, open a panel and click the button, and you see the problem. Also same problem when you remove data from the list. If you have one panel open, and you remove it, the sibling is suddenly open.
How do I attack this problem?
Per the docs the value
prop of the v-expansion-panels
component:
Controls the opened/closed state of content in the expansion-panel. Corresponds to a zero-based index of the currently opened content. If the
multiple
prop (previouslyexpand
in 1.5.x) is used then it is an array of numbers where each entry corresponds to the index of the opened content. The index order is not relevant.
That means that which panel(s) are open has no connection to their content. If you reverse or change the order of the items
array, you also need to update the panel array to adjust the open indexes accordingly:
methods: {
changeOrder () {
// reverse the elements in your items array
this.items = this.items.reverse()
// get the max index of elements in your items array
const maxIndex = this.items.length - 1
// set index of each open panel to its inverse
this.panel = this.panel.map(p => maxIndex - p)
},
removeItem () {
this.items.splice(0, 1)
// since the index of each item will be effectively reduced by 1
//
this.panel = this.panel.map(p => p - 1)
},
}