Ensure that Vue.js Accordion items do not auto-close when a different item is selected

I'm looking to create an Accordion menu using vuejs. The requirement is for the Accordion to stay open even if another div is clicked, and to only close when the Accordion item itself is clicked. How can I achieve this?

Here is the vue code:

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

And here is the HTML code:

<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>

Answer №1

It is essential to maintain a list of top-level menu items that should be displayed or hidden. Consider the example below:

https://codesandbox.io/s/jovial-carson-n2exv?file=/src/App.vue

<template>
  <div id="app">
    <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"
      >
        <a class="title" @click="toggleAccordion(menu.item_name)">{{
          menu.item_name
        }}</a>
        <ul
          class="level-1-wrp"
          v-if="menu.childrens && displayArray[menu.item_name]"
        >
          <li
            class="level-1"
            v-for="(submenuone, indexone) in menu.childrens"
            :key="indexone"
          >
            <a class="title">{{ submenuone.item_name }}</a>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  components: {},
  data() {
    return {
      isOpen: false,
      selected: "",
      displayArray: {},
      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) {
      if (this.displayArray[item] === undefined) {
        this.$set(this.displayArray, item, true);
      } else {
        this.$set(this.displayArray, item, !this.displayArray[item]);
      }
    },
  },
  computed: {
    accordionClasses() {
      return {
        "is-closed": !this.isOpen,
        "is-primary": this.isOpen,
        "is-dark": !this.isOpen,
      };
    },
  },
};
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Vue component's computed property not responding as expected

I am currently working on two components: OperatorsList and OperatorButton. The OperatorsList consists of buttons, and when I click on a button, I want to update some data: I emit select with the operator.id This event is captured by the OperatorList c ...

Is it possible to alter the page color using radio buttons and Vue.js?

How can I implement a feature to allow users to change the page color using radio buttons in Vue.js? This is what I have so far: JavaScript var theme = new Vue({ el: '#theme', data: { picked: '' } }) HTML <div ...

Incorporating the Revolution Slider jQuery plugin within a Vue.js environment

Currently, my goal is to transform an html project into a vue application. The initial project utilizes a jquery plugin for Revolution slider by including them through script tags in the body of the html file and then initializing them: <script type= ...

Limiting the table width in TinyMCE

Currently, I am utilizing TinyMCE within a Vue application. I've set up TinyMCE with the table_grid: false configuration, causing a dialog to appear when a table is created. This dialog allows users to specify rows, columns, width, and more. Within t ...

What is the correct way to utilize the Vuex mutation payload object effectively?

I have two input fields where I can enter a value to search for either the name of a company or the location. The search functionality works when only one argument is provided in the foundJobs mutation and action. However, when the payload contains an obje ...

Deleting a record by sending an HTTP request and then removing the corresponding object from an array in Vue.js

After successfully solving this particular issue with the help of @nils, I have encountered a new question that I hope someone can assist me with! My current situation involves having a list of records from which I can select and remove items with just on ...

The proper method for utilizing the clipped prop on the <v-navigation-bar/> component within Vuetify is as follows

Looking for the correct way to apply the clipped prop to <v-navigation-draw/> in a Vuetify application in order to ensure that the navigation drawer sits below the app-bar. Here is what I have tried so far. Started with a new project: $ vue create ...

Issue with Vue data table where the row's q-input does not retain the values of the model

For access to the code, please visit the azure link for the built code and check out the source code on github. In this particular scenario, I am utilizing a q-datatable from Quasar Framework. The data is structured in nested form with primary data displ ...

What steps can I take to prevent Vue from rendering template comments?

Recently, I have been working with a Vue application (version 2.6.0) and started adding comments to the templates using this syntax: <--! This comment describes what this component does --> The problem is that these comments are now appeari ...

Enabling a mat-slide-toggle to be automatically set to true using formControl

Is there a way to ensure that the mat-slide-toggle remains true under certain conditions? I am looking for a functionality similar to forcedTrue="someCondition". <mat-slide-toggle formControlName="compression" class="m ...

Injecting environment variables into webpack configuration

My goal is to set a BACKEND environment variable in order for our VueJS project to communicate with the API hosted there, but I keep receiving an error message saying Unexpected token :. Here is the current code snippet from our config/dev.env.js, and I&a ...

Using Vue.js, you can set a method to return data directly to

Having just begun my journey with Vue, I find myself in a bit of a predicament. As part of my learning process, I am developing an app for tracking episodes in TV series. The initial step involves searching for series and adding them to a database. When co ...

How many times can vue.js v-for iterate through a variable?

Looking to loop through rows in a table using a range? Most examples show how to do this for a fixed value, like: <div> <span v-for="n in 10">{{ n }} </span> </di But what if you want to achieve this with a variable like below? &l ...

I am having difficulty creating grid-template-columns in Vue

When I placed my code in the style scoped section... This is the desired output that I'm aiming for: .user-grid{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 1rem; } .user-car ...

Ways to verify whether a vue instance is empty within a .vue file by utilizing the v-if directive

I am facing an issue with a for-loop in Vue that iterates through a media object using v-for to check if it contains any images. Everything is working correctly, but I want to display a div below the loop saying "There is no media" when the object is empty ...

Exploring the MEVN Stack's Integration with Image Uploading

After successfully implementing an image upload system on my website, I encountered difficulty in linking to the uploaded images. The root directory of my project includes a client folder for vuejs app and a server folder for backend logic. When users upl ...

Tips for prioritizing new data input at the top of the list

Hey there, I'm having trouble figuring out how to push new data to the top of a list using vue.js and laravel. I've been trying but haven't had any luck so far. If anyone could lend a hand, I would greatly appreciate it. Below is my Control ...

Utilize the @blur event within flatpickr to trigger actions when the output is empty

<b-col md="7" offset-md="1"> <b-form-group> <template> Date and Time <flat-pickr id="datetime" v-model="datetime" class="form-control" ...

Using Vue router to dynamically define the query key when calling router.push()

Hello, I am relatively new to using Vue and have been working on a project that involves making GET requests based on the current URL. In one of my functions, I am trying to dynamically set the value of filterType in the query key within the router.push() ...

Difficulty clearing dictionary in Vue.js causing issues with the DOM not updating

Check out this jsfiddle example I am working with a dictionary in Vue and using a v-for loop to render its items. I want to clear the dictionary, but simply setting it to an empty object or deleting keys doesn't trigger a re-render in the DOM. Any su ...