Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VueJs set active class, when one li element clicked in v-for loop

I can't figure out how to properly select (set active class) when I do v-for loop and one class is already selected. Let me share the code and with further explanation

These are my available subscriptions and one is already selected, based on user data

<ul>
    <li v-for="(s, key, index) in subscriptions"
        :class="checkIfClassActive(s.subscription_key)"
        @click="setActive(key, index)">
        {{ s.name }}
    </li>
</ul>

and my js code

checkIfClassActive(userSubscriptionKey) {
    if (userSubscriptionKey === this.userSubscription.subscription_key) {
        return 'active';
    }
},
setActive(key, index) {

},

And this is how is displayed enter image description here

Now the next step is when I click on one li element it should become active and all other li elements should lose active class, but the problem is that I can't figure out how to properly write setActive function. Can you please help me out, how to do this.

If you need any additional informations, let me know and I will provide. Thank you!

like image 970
Valor_ Avatar asked Aug 09 '18 19:08

Valor_


4 Answers

Add a data property called activeIndex:

  data() {
    return {
      activeIndex: undefined
    }
  },

and your setActive method:

  methods: {
    setActive(subscription, index) { 
      this.activeIndex = index;
      this.userSubscription.subscription_key = subscription.subscription_key
},
    getSubscriptions() {
       .....
       // fetch subscriptions in this.subscriptions var
       .....
       // select preselected subscription, when fetching subscriptions 
       let userSubscriptionKey = this.userSubscription.subscription_key;
       let indexOfObject = this.subscriptions.findIndex(
            o => o.subscription_key === userSubscriptionKey
       );
       this.setActive(this.userSubscription, indexOfObject);

    }
  }

with a slight modification to your template:

<ul>
    <li v-for="(s, index) in subscriptions"
        :class="{ 'active': activeIndex === index }" :key="s.id"
        @click="setActive(s, index)">
        {{ s.name }}
    </li>
</ul>

You basically set an index that should be active and that's it. active css class is added when list element's index is the same as activeIndex.

As for setting activeIndex to existing choice before the user changes it, you can set activeIndex when fetching subscriptions data to user's current subscription.

Fiddle: http://jsfiddle.net/eywraw8t/256701/

like image 187
dziraf Avatar answered Sep 22 '22 17:09

dziraf


Change your this.userSubscription.subscription_key variable everytime a tab is selected. For this pass it through setActive(s.subscription_key) You can do something like this,

<li v-for="(s, key, index) in subscriptions"
        :class="checkIfClassActive(s.subscription_key)"
        @click="setActive(s.subscription_key)">
        {{ s.name }}
</li>

Js

checkIfClassActive(userSubscriptionKey) {
    if (userSubscriptionKey === this.userSubscription.subscription_key) {
        return 'active';
    }
},
setActive(subscription_key) {
    this.userSubscription.subscription_key=subscription_key;
},
like image 31
Helping hand Avatar answered Sep 25 '22 17:09

Helping hand


this is quicly

if you use v-for:

            <template>
                <div>
                    <ul>
                        <li 
                        class="anyThings"
                        v-for="cat in cats"
                        :key="cat.index"
                        @click="itemActive(cat.index)"
                        :class="[(itemA == cat.index) ? 'active':'']"
                        >{{ cat.yourObjectKey }}
                        </li>
                    </ul>
                </div>
            </template>

            <script>
                export default {
                    data() {
                        return {
                            itemA:'0' // for first load and in curent path
                        }
                    },
                    computed: {
                        cats() {
                            ...
                        }
                    },
                    methods: {
                        itemActive(e) {
                            this.itemA = e;
                        }
                    },

                }
            </script>

            <style>
                .active {
                    ...
                }
            </style>

if you don't need use v-for and use router-link in element:

            <template>
                <div>
                    <ul>
                        <li @click="itemActive($route.path)">
                            <router-link to="/" class="anyThings" 
                            :class="[(itemA == '/') ? 'active':'']"
                            >your text
                            </router-link>  
                        </li>
                        <li @click="itemActive($route.path)">
                            <router-link to="/article" class="anyThings" 
                            :class="[(itemA == '/article') ? 'active':'']"
                            >your text
                            </router-link>  
                        </li>
                         .
                         .
                         .
                    </ul>
                </div>
            </template>

            <script>
                export default {
                    data() {
                        return {
                            itemA:this.$route.path // for first load and in curent path
                        }
                    },
                    methods: {
                        itemActive(e) {
                            this.itemA = e;
                        }
                    },

                }
            </script>

            <style>
                .active {
                    ...
                }
            </style>
like image 29
hilo Avatar answered Sep 26 '22 17:09

hilo


A simple example showing the logic:

html part:

<div id="app">
  <ul>
    <li 
    v-for="item in items"
    :key="item.id"
    :class="item.class"
    @click="set_active_id(item.id)"
    >{{ item.text }}</li>
  </ul>
</div>

Js part:

new Vue({
  el: "#app",
  data: {
    items: [
      { id: 1, text: 'text1', class: 'active' }, //default active
      { id: 2, text: 'text2', class: '' },
      { id: 3, text: 'text3', class: '' }
    ],
    previous_active_id: 1
  },
  methods: {
    set_active_id(id) {
      if (this.previous_active_id === id) return //no need to go further
      this.items.find(item => item.id === this.previous_active_id).class = '' //remove the active class from old active li
      this.items.find(item => item.id === id).class = 'active' //set active class to new li
      this.previous_active_id = id //store the new active li id
    }
  }
})

See it in action

like image 38
Roland Avatar answered Sep 26 '22 17:09

Roland