Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue js toggle class of each individual element

While there are many examples of toggling classes in Vuejs, I am yet to find one that toggles a class narrowing down the scope of the element. If I define a global variable like this:

data: {
  toggle: false
}

I will run into a problem when I have an element, like this navigation bar:

<ul class="menu">
  <li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
    Foo
    <ul class="dropdown">
      <li>Dropdown Item 1</li>
      <li>Dropdown Item 2</li>
    </ul>
  </li>
  <li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
    Bar
    <ul class="dropdown">
      <li>Dropdown Item 1</li>
      <li>Dropdown Item 2</li>
    </ul>
  </li>
</ul>

See what happens here? If I click in one of these two elements, both are going to toggle the class at the same time, because it's changing a global variable. Now, how would I toggle the class of only the element that is clicked?

like image 573
harrypujols Avatar asked Nov 28 '22 20:11

harrypujols


2 Answers

It boggles my mind that something so simple requires so much code using modern frameworks, and it's a reason why JavaScript development is becoming so complex. I resorted to using a plain-old JavaScript listener to solve the matter.

<li class="has-dropdown" @click="toggle">
    ...
</li>
...

methods: {
 toggle: function( event ) {
   event.target.classList.toggle('is-open')
 }
}

...
like image 109
harrypujols Avatar answered Nov 30 '22 10:11

harrypujols


This is just a small example of what @SLaks mentioned in his answer. Essentially turn the list elements into their own components so they can have their own state.

Vue.component("clicktoggle", {
  template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
  data() {return {toggle: false}}
})

And here is how it's used.

console.clear()

Vue.component("clicktoggle", {
  template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
  data() {return {toggle: false}}
})

new Vue({
  el:"#app"
})
.has-dropdown {
  cursor: pointer;
}
.has-dropdown:not(.is-open) ul {
  display: none
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <ul class="menu">
    <li class="has-dropdown" is="clicktoggle">
      Foo
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </li>
    <clicktoggle class="has-dropdown">
      Bar
      <ul class="dropdown">
        <li>Dropdown Item 1</li>
        <li>Dropdown Item 2</li>
      </ul>
    </clicktoggle>
  </ul>
</div>

Vue makes it incredibly simple to knock out little components like this. One quick possible enhancement would be to add a property to specify what class you wanted to toggle.

like image 31
Bert Avatar answered Nov 30 '22 10:11

Bert