0

I am new to Vue and I am trying to display a list of cards. The cards will be broken out into rows of three. That works, but I want to give each row a different class name based on a list of classes in an array but can't seem to figure out how to do that with what I have right now.

I tried using v-bind:class on the row but not sure if that is the way to go with what I am trying to do.

Here is what my HTML structure looks like:

<div class="row" v-for="i in row”>
  <div v-for="(show, index) in rowItems(i)" class="card" v-bind:class="{ new: item.new }">
  <img v-bind:src="item.illustration">
    <p>{{ item.name }}</p>
  </div>
</div>

Here is what I have in Vue. My data is in an object (itemList).

let app = new Vue({
  el: '#container',
  data: {
    rowItems: 3,
    items: itemList,
    rowClasses: ['row1', 'row2', 'row3', 'row4']
  },
  computed:{
    row:function(){     
      return Math.ceil(this.items.length / this.rowItems);
    },
  },
  methods:{
    rowItems:function(index){
     return this.items.slice((index - 1) * this.rowItems, index * this.rowItems)
    }
  }
});
1
  • 1
    I notice rowItems is both a method and a data item. Commented Jul 27, 2018 at 21:03

1 Answer 1

3

You can v-bind the class using object syntax like this:

<div :class="{ new: item.new, [rowClasses[index]]: true }">

new Vue({
  el: '#app',
  data() {
    return {
      rowCount: 3,
      items: [
        { name: 'A', new: false },
        { name: 'B', new: false },
        { name: 'C', new: true },
        { name: 'D', new: false },
      ],
      rowClasses: ['row1', 'row2', 'row3', 'row4']
    };
  },
  computed: {
    row() {     
      return Math.ceil(this.items.length / this.rowCount);
    },
  },
  methods: {
    rowItems(index) {
      return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
    },
  }
})
.card {
  border: solid 1px gray;
  margin: 10px;
  padding: 10px;
}
.new {
  background-color: lightyellow;
}
.row1 {
  color: red;
}
.row2 {
  color: green;
}
.row3 {
  color: blue;
}
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">  
  <div class="row" v-for="i in row">
    <div v-for="(item, index) in rowItems(i)"
         class="card"
         :class="{ new: item.new, [rowClasses[index]]: true }">
      <pre>{ new: {{item.new}}, [{{rowClasses[index]}}]: true }</pre>
      <p>{{ item.name }}</p>
    </div>
  </div>
</div>

Or you can call a method that returns such an object:

// <template>
<div :class="getRowClass(item, index)">

// <script>
methods: {
  getRowClass(item, index) {
    return {
      new: item.new,
      [this.rowClasses[index]]: true
    };
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      rowCount: 3,
      items: [
        { name: 'A', new: false },
        { name: 'B', new: false },
        { name: 'C', new: true },
        { name: 'D', new: false },
      ],
      rowClasses: ['row1', 'row2', 'row3', 'row4']
    };
  },
  computed: {
    row() {     
      return Math.ceil(this.items.length / this.rowCount);
    },
  },
  methods: {
    rowItems(index) {
      return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
    },
    getRowClass(item, index) {
      const rowClass = this.rowClasses[index % this.rowClasses.length];
      return {
         new: item.new,
         [rowClass]: true
      };
    }
  }
})
.card {
  border: solid 1px gray;
  margin: 10px;
  padding: 10px;
}
.new {
  background-color: lightyellow;
}
.row1 {
  color: red;
}
.row2 {
  color: green;
}
.row3 {
  color: blue;
}
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">  
  <div class="row" v-for="i in row">
    <div v-for="(item, index) in rowItems(i)"
         class="card"
         :class="getRowClass(item, index)">
      <pre>{{getRowClass(item, index)}}</pre>
      <p>{{ item.name }}</p>
    </div>
  </div>
</div>

Or you can do this entirely in CSS, using nth-of-type() and eliminating the need for rowClasses[].

// <style>
.card:nth-of-type(1n) {}   // every 1st card
.card:nth-of-type(2n) {}   // every 2nd card
.card:nth-of-type(3n) {}   // every 3rd card

new Vue({
  el: '#app',
  data() {
    return {
      rowCount: 3,
      items: [
        { name: 'A', new: false },
        { name: 'B', new: false },
        { name: 'C', new: true },
        { name: 'D', new: false },
      ],
    };
  },
  computed: {
    row() {     
      return Math.ceil(this.items.length / this.rowCount);
    }
  },
  methods: {
    rowItems(index) {
      return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
    }
  }
})
.card {
  border: solid 1px gray;
  margin: 10px;
  padding: 10px;
}
.new {
  background-color: lightyellow;
}
.card:nth-of-type(1n) {
  color: red;
}
.card:nth-of-type(2n) {
  color: green;
}
.card:nth-of-type(3n) {
  color: blue;
}
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">  
  <div class="row" v-for="i in row">
    <div v-for="(item, index) in rowItems(i)"
         class="card"
         :class="{ new: item.new }">
      <pre>.card:nth-of-type({{ index+1 }}n)</pre>
      <p>{{ item.name }}</p>
    </div>
  </div>
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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