Using Vue.js to dynamically add classes based on an array

Just diving into Vue and experimenting with displaying a grid of cards. I've managed to group them into rows of three, but now I want each row to have a distinct class assigned from an array of classes. However, I'm a bit stuck on how to achieve this with my current setup.

I attempted to use v-bind:class on the row element, but I'm unsure if that's the right approach for what I have in mind.

This is how my HTML structure looks:

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

And here's my Vue code. The data is stored in an object called itemList.

let app = new Vue({
  el: '#container',
  data: {
    rowItems: 3,
    items: itemList,
    rowClasses: ['row1', 'row2', 'row3', 'row4']
  },
  computed:{
    rows:function(){     
      return Math.ceil(this.items.length / this.rowItems);
    },
  },
  methods:{
    getRowItems:function(index){
     return this.items.slice((index - 1) * this.rowItems, index * this.rowItems)
    }
  }
});

Answer №1

To apply classes using object syntax in Vue, you can use the v-bind directive like so:

<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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4533302005776b706b7473">[email protected]</a>"></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>

You can also create a method that returns an object for applying classes dynamically:

// <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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e1979484a1d3cfd4cfd0d7">[email protected]</a>"></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>

An alternative approach is to utilize CSS only by using :nth-of-type() without 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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f1878494b1c3dfc4dfc0c7">[email protected]</a>"></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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Docker Image with docker-compose is successful, however, it seems to encounter issues when used directly with Docker

Hello, I am posting this because I have encountered a unique issue where the image works in Docker but not with docker-compose. My project is a full-stack application using React, Node, and Mongo. When I run docker-compose up, everything runs smoothly as ...

CSS - Help! Seeing different results on Internet Explorer

I'm currently handling an OSCommerce website, and I'm trying to figure out why this issue is occurring. You can view the website at this link: The layout looks completely different on Internet Explorer, and I'm puzzled as everything should ...

blur event triggered on a cell within a table

Currently, I am using the code snippet below to populate data using a data table. My goal is to be able to edit the data in one of the columns and then validate the value after editing using the onblur event. I attempted to call the onblur event on the t ...

When using Vue 3 with Laravel Blade template, issues arise when trying to generate a production build

When working with Vue 3 SFC and trying to embed the template inside a Laravel Blade file, it can be a bit tricky. Take for example this usage scenario: Test.vue <script setup> import { ref} from 'vue'; const testValue = ref('Works&a ...

Importing modules using relative paths results in failure due to module not being found, whereas employing absolute paths

I have been encountering this problem for a considerable amount of time and have made multiple attempts to resolve it. I am currently working on the development of my discord.js bot and recently switched from TS back to JS due to certain complications I fa ...

Modify the Color of Mesh by Clicking a Button in THREE.js

Having trouble changing the color of a sphere mesh in three.js when a button is pressed. When using mesh.material.color.SetHex() with a Click event listener, it doesn't work. However, it works fine when used outside the event listener. Here's my ...

Navigating Bootstrap: Refreshing a full-screen modal with a swipe gesture on mobile devices

I'm currently utilizing Bootstrap 5's full screen modal and I'm exploring how to implement a feature that enables refreshing on mobile devices by swiping down, similar to how you would usually refresh a page. <script src="https://cdn.j ...

`Transpose a 1-dimensional array using Numpy`

Here is some code that demonstrates the functionality I am looking for using simple sample data. I used np.digitize to bin the data and then computed a column index based on this explanation. It should be noted that bin_idx never decreases, in case that ...

Take action once all deferred operations have been successfully completed

Below is the code snippet I am working with: loadOpportunities: function () { return $.getJSON("/Opportunity/GetAll").pipe(function (result) { //do stuff }); }, loadTypes: function () { return $.getJSON("/OpportunityTypes/GetAll", nul ...

Run JavaScript code that is retrieved through an ajax request in Ruby on Rails

When I use Rails to render a javascript view, the code looks like this: $("##{@organization.id}-organization-introtext").hide(); $("##{@organization.id}-organization-full").append("#{escape_javascript(render @organization)}").hide().fadeIn('slow&apos ...

Encountering PhantomJS glitch during routine testing

My experience with the node-phantom npm module has been a bit perplexing. For instance, when running a straightforward test like this: phantom=require('node-phantom'); var phantom=require('node-phantom'); phantom.create(function(err,ph ...

What is the best approach for managing interactive infographics using JavaScript?

I've been tasked with a project that involves creating a dynamic data visualization using JavaScript. You can check out the final product here. The goal is to take information from a provided PDF and find a way to display it dynamically on an image. ...

The JavaScript feature designed for activating modal popups is only effective for the initial item

I am in the process of developing a clothing shopping website where the main page displays various clothing items. Each garment has an "Add to Cart" button that triggers a popup modal when clicked. However, I am encountering an issue where the modal only ...

Facing difficulty in uploading image to local server using Froala editor

For testing purposes, I've been attempting to upload images using the Froala WYSIWYG editor on my localhost, but unfortunately, it's not functioning as expected. After selecting an image to upload, it briefly appears faded in the editor and then ...

Tips on how to convert a select box to an unordered list using mdb.min.js

Our project utilizes HTML with the mdb.min.js library, which converts all <select> tags to <ul><li> format. An issue arises when setting a piece of HTML code via AJAX in a div element. In this scenario, select boxes do not appear as they ...

unable to connect css file to document

My index.html file is not reading the style.css file for some reason, even though it is linked. I have added the type and checked the path, but still facing issues. Can anyone help troubleshoot this problem? Thank you. https://i.sstatic.net/xxpBV.png htt ...

Automatically fill in Vue files

Is there a quick way in Vue to automatically populate an empty file with the template, script, and style tags along with default content? For example, in VS Code you can use the shortcut ! + Enter to insert all necessary HTML tags/codes. I'm wonderin ...

Utilizing vue for seamless global dialog integration

I'm looking for a versatile, universal dialog/modal component to incorporate into my Vue application. I want to be able to access it from any component and easily update the header text, body text, and callback function when the dismiss button is clic ...

Troubleshooting: Issues with jQuery's add/removeClass function and AJAX functionality

Currently, I am utilizing Isotope along with AJAX to fetch some WordPress posts. Everything seems to be functioning correctly, except that the default Isotope animation runs when new content is loaded via AJAX, which appears somewhat awkward. Although, I s ...

Can you provide guidance on effectively utilizing a Pinia store with Vue3, Pinia, and Typescript?

I'm currently facing challenges while using the Pinia store with TypeScript and implementing the store within a basic app.vue Vuejs3 option api. Here is my app.js file: import {createApp} from 'vue' import {createPinia} from "pinia&quo ...