Valor_
Valor_

Reputation: 3591

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!

Upvotes: 7

Views: 27219

Answers (5)

eons
eons

Reputation: 456

I had this problem the simplest answer is to change the "li" tags to "router-link", then change the default styling of the router-link. In this case "router-link-active"

<ul>
   <router-link v-for="item in items"
     :key="item.id"
     :to="item.route"
    >
        {{ s.name }}
      </router-link>
   </ul>


 <style>
   .router-link-active{
     ...
   }
 </style>

Upvotes: 0

hilo
hilo

Reputation: 11

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>

Upvotes: 1

dziraf
dziraf

Reputation: 3653

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/

Upvotes: 28

Roland
Roland

Reputation: 27719

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

Upvotes: 1

Helping hand
Helping hand

Reputation: 2920

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;
},

Upvotes: 4

Related Questions