Home > Mobile >  Vue.js: Accordion is not working in for loop
Vue.js: Accordion is not working in for loop

Time:10-05

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.

enter image description here

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.

  • Related