I added accordion for a single item and it was working fine, but then I added in for loop and now when I click on any item, all items are getting expanded.
<template>
<ul class="level-0-wrp" v-if="headerDesktopMenu.menu.menu_items">
<li class="level-0" v-for="(menu, index) in headerDesktopMenu.menu.menu_items" :key="index" :class="accordionClasses" v-if="headerDesktopMenu.menu.menu_items">
<a class="title" @click="toggleAccordion">{{ menu.item_name }}</a>
<ul class="level-1-wrp" v-if="menu.childrens">
<li class="level-1" v-for="(submenuone, indexone) in menu.childrens" :key="indexone" v-if="menu.childrens">
<a class="title">{{ submenuone.item_name }}</a>
</li>
</ul>
</li>
</ul>
</template>
<script>
export default {
data () {
return {
isOpen: false
}
},
methods: {
toggleAccordion () {
this.isOpen = !this.isOpen;
}
},
computed: {
accordionClasses () {
return {
'is-closed': !this.isOpen,
'is-primary': this.isOpen,
'is-dark': !this.isOpen
};
}
}
}
As given in this picture, If I click on men, women, and accessories get expanded.
CodePudding user response:
Try like following snippet:
You can add another data property selected: ''
, then in template toggle accordion v-if="isOpen && menu.item_name === selected"
. In method you set selected:
toggleAccordion (item) {
item == this.selected ? this.isOpen = !this.isOpen : this.isOpen = true
this.selected = item
}`
new Vue({
el: '#demo',
data () {
return {
isOpen: false,
selected: '',
headerDesktopMenu: {
menu: {
menu_items: [{item_name:11111, childrens: [{item_name: 11}, {item_name: 12}]},{item_name:22222, childrens: [{item_name: 21}, {item_name: 22}]},{item_name:33333, childrens: [{item_name: 31}, {item_name: 32}]},{item_name:44444, childrens: [{item_name: 41}, {item_name: 42}]}]
}
}
}
},
methods: {
toggleAccordion (item) {
item == this.selected ? this.isOpen = !this.isOpen : this.isOpen = true
this.selected = item
}
},
computed: {
accordionClasses () {
return {
'is-closed': !this.isOpen,
'is-primary': this.isOpen,
'is-dark': !this.isOpen
};
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<ul class="level-0-wrp" v-if="headerDesktopMenu.menu.menu_items">
<li class="level-0" v-for="(menu, index) in headerDesktopMenu.menu.menu_items" :key="index" :class="accordionClasses" v-if="headerDesktopMenu.menu.menu_items">
<a class="title" @click="toggleAccordion(menu.item_name)">{{ menu.item_name }}</a>
<ul class="level-1-wrp" v-if="menu.childrens">
<li class="level-1" v-for="(submenuone, indexone) in menu.childrens" :key="indexone" v-if="isOpen && menu.item_name === selected">
<a class="title">{{ submenuone.item_name }}</a>
</li>
</ul>
</li>
</ul>
</div>
CodePudding user response:
You have set @click="toggleAccordion"
to all items. To fix your problem, every item needs it own state. This, for example, could be done like that:
First, provide your state as an object
:
return {
isOpen: {}
}
As I don´t know the structure of your data, I just did this example with a simple array
of objects
like this:
testObject: [
{name: "hello1"},
{name: "hello2"},
{name: "hello3"},
{name: "hello4"}
]
Just loop trough this in created
to generate a state for all, like this:
for(let itemId in this.testObject) {
Object.assign(this.isOpen, {[itemId]: false})
}
The object
isOpen
now looks like this:
{
"0":false,
"1":false,
"2":false,
"3":false
}
Now you can call toggleAccordion
with the index
from your loop, like toggleAccordion(index)
and change the function to this:
toggleAccordion(index) {
this.isOpen[index] = !this.isOpen[index];
}
Where you applied isOpen
before you just apply isOpen[index]
now.