2

I'm making a list of items with v-for loop. I have some API data from server.

items: [
   {
       foo: 'something',
       number: 1
   },
   {
       foo: 'anything',
       number: 2
   }
]

and my template is:

<div v-for(item,index) in items @click=toggleActive>
     {{ item.foo }} 
     {{ item.number }} 
</div>

JS:

methods: {
    toggleActive() {
        //
    }
}

How can i toggle active class with :class={active : something} ? P.S I don't have boolean value in items

1
  • without moving item in separate component Commented Aug 7, 2018 at 10:39

4 Answers 4

3

You can try to implement something like:

<div 
  v-for="(item, index) in items"
  v-bind:key="item.id" // or alternativelly use `index`.
  v-bind:class={'active': activeItem[item.id]}
  @click="toggleActive(item)"
>

JS:

data: () => ({ 
  activeItem: {}, 
}),

methods: {
  toggleActive(item) {
    if (this.activeItem[item.id]) {
      this.removeActiveItem(item);

      return;
    }

    this.addActiveItem(item);
  },
  addActiveItem(item) {
    this.activeItem = Object.assign({},
      this.activeItem,
      [item.id]: item,
    );
  },
  removeActiveItem(item) {
    delete this.activeItem[item.id];
    this.activeItem = Object.assign({}, this.activeItem);
  },
}
Sign up to request clarification or add additional context in comments.

3 Comments

It's worked incorrent. When i try click to another item, previous class unpined. I need to select multiple elements, and on item second click, unpined active class
this.activeItem underfined, and what is " [item.id]: item " in addActiveItem method?
There was a typo. [item.id]: item is basically a way of dynamically setting a property key in an object. It is a new Javascript feature introduced in the ES6 version called Computed property names. So, if the value of item.id is for instance 'fooText', the object will looks like { 'fooText': item }. For further readings: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… stackoverflow.com/questions/2462800/…
0

I had the same issue and while it isn't easy to find a whole lot of useful information it is relatively simple to implement. I have a list of stores that map to a sort of tag cloud of clickable buttons. When one of them is clicked the "added" class is added to the link. The markup:

<div class="col-sm-10">
    <a href="#" class="tagCloud" v-for="store in stores" v-on:click="toggleAdd(store)" v-bind:class="{ 'added': selectedStoreIds.indexOf(store.id) !== -1 }">{{ store.name }}</a>
</div>

And the associated script (TypeScript in this case). toggleAdd adds or removes the store id from selectedStoreIds and the class is updated automatically:

new Vue({
    el: "#productPage",
    data: {
        stores: [] as StoreModel[],
        selectedStoreIds: [] as string[],
    },
    methods: {
        toggleAdd(store: StoreModel) {
            let idx = this.selectedStoreIds.indexOf(store.id);
            if (idx !== -1) {
                this.selectedStoreIds.splice(idx, 1);
            } else {
                this.selectedStoreIds.push(store.id);
            }
    },
    async mounted () {
        this.stores = await this.getStores(); // ajax request to retrieve stores from server
    }
});

Marlon Barcarol's answer helped a lot to resolve this for me.

Comments

0

It can be done in 2 steps.

1) Create v-for loop in parent component, like

<myComponent v-for="item in itemsList"/>

data() {
  return {
    itemsList: ['itemOne', 'itemTwo', 'itemThree']
  }
}

2) Create child myComponent itself with all necessary logic

<div :class="someClass" @click="toggleClass"></div>

data(){
  return {
    someClass: "classOne"
  }
},
methods: {
  toggleClass() {
    this.someClass = "classTwo";
  }
}

This way all elements in v-for loop will have separate logic, not concerning sibling elements

Comments

0

I was working on a project and I had the same requirement, here is the code:

You can ignore CSS and pick the vue logic :)

new Vue({
  el: '#app',
  data: {
    items: [{ title: 'Finance', isActive: false }, { title: 'Advertisement', isActive: false }, { title: 'Marketing', isActive: false }],
  },
})
body{background:#161616}.p-wrap{color:#bdbdbd;width:320px;background:#161616;min-height:500px;border:1px solid #ccc;padding:15px}.angle-down svg{width:20px;height:20px}.p-card.is-open .angle-down svg{transform:rotate(180deg)}.c-card,.p-card{background:#2f2f2f;padding:10px;border-bottom:1px solid #666}.c-card{height:90px}.c-card:first-child,.p-card:first-child{border-radius:8px 8px 0 0}.c-card:first-child{margin-top:10px}.c-card:last-child,.p-card:last-child{border-radius:0 0 8px 8px;border-bottom:none}.p-title .avatar{background-color:#8d6e92;width:40px;height:40px;border-radius:50%}.p-card.is-open .p-title .avatar{width:20px;height:20px}.p-card.is-open{padding:20px 0;background-color:transparent}.p-card.is-open:first-child{padding:10px 0 20px}.p-card.is-open:last-child{padding:20px 0 0}.p-body{display:none}.p-card.is-open .p-body{display:block}.sec-title{font-size:12px;margin-bottom:10px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<div id="app" class="p-5">
  <div class="p-wrap mx-auto">
    <div class="sec-title">NEED TO ADD SECTION TITLE HERE</div>
    <div>
      <div v-for="(item, index) in items" v-bind:key="index" class="p-card" v-bind:class="{'is-open': item.isActive}"
        v-on:click="item.isActive = !item.isActive">
        <div class="row p-title align-items-center">
          <div class="col-auto">
            <div class="avatar"></div>
          </div>
          <div class="col pl-0">
            <div class="title">{{item.title}}</div>
          </div>
          <div class="col-auto">
            <div class="angle-down">
              <svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="angle-down" role="img"
                xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"
                class="svg-inline--fa fa-angle-down fa-w-10 fa-3x">
                <path fill="currentColor"
                  d="M151.5 347.8L3.5 201c-4.7-4.7-4.7-12.3 0-17l19.8-19.8c4.7-4.7 12.3-4.7 17 0L160 282.7l119.7-118.5c4.7-4.7 12.3-4.7 17 0l19.8 19.8c4.7 4.7 4.7 12.3 0 17l-148 146.8c-4.7 4.7-12.3 4.7-17 0z"
                  class=""></path>
              </svg>
            </div>
          </div>
        </div>
        <div class="p-body">
          <div class="c-card"></div>
          <div class="c-card"></div>
          <div class="c-card"></div>
        </div>
      </div>
    </div>
  </div>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.