What is the best way to modify the style class of a specific item within a v-for loop?

While there are similar questions out there, none of them quite address what I'm looking for (or maybe I just don't fully understand them and if that's the case, my apologies). Here is one example, but it seems to be related to Vue.JS 3 which I am struggling to adapt to my code, even though the requirement remains the same.

My goal is to change the background color of individual items in a v-for loop based on the selection made from a drop-down menu. Currently, all items change color whenever the drop-down selection changes.

You can view the project on Codepen.io here: https://codepen.io/Salixa/pen/jOQPRNz. To see the list, you need to input a name, click 'Add Player', and then 'Check Availability'. When you select an option from the drop-down, it changes the class for each item in the list. You can also add availability to get an idea of what it should look like!

Current behavior: Screenshot demonstrating current behavior on codepen.io Ideal behavior: Screenshot demonstrating ideal behavior on codepen.io

The issue lies with a v-for block iterating over values in an object (within an array). Each value corresponds to a selection box. The predefined values render with the correct color class, as expected. However, when I change the selection, the color class applies to all items, which is not the desired outcome.

This is the current HTML code:

<div id="displayAvailability" v-for="(value, key, index) in player" :key="index">
      <div :id="'listItem'+index+1" :class="[selection != '' ? {available:selection==='Available', tentative:selection==='Tentative', busy:selection==='Busy', session:selection==='Session', unknown:selection==='Unknown'} : {available:value==='available', tentative:value==='tentative', busy:value==='busy', session:value==='session',unknown:value==='Unknown'}]" :key="index">
        <select id="availabilityOptions" @change="updateColour($event)" >
          <option>{{value}}</option>
          <option v-model="selection">Available</option>
          <option v-model="selection">Busy</option>
          <option v-model="selection">Tentative</option>
          <option v-model="selection">Session</option>
        </select>
      </div>
    </div>

This JavaScript snippet controls the color change:

updateColour(event){
      this.selection = event.target.value;
      console.log(this.selection);
      return this.selection;
    }

The problem arises because 'selection' gets changed to the selected option, affecting the style of all items since it's applied to the div for each item. Is there a way to change only the individual item?

Note: I don't want to update the player object with the new selection. In the future, I plan to have default availability and allow each player to update availability individually for each day. Additionally, I'm working with Vue.JS 2 due to work constraints and the need to learn it better. The random placement of keys and indexes in some parts of the code is me trying to learn from other StackOverflow responses, as I'm still pretty new to this and not entirely confident about understanding everything correctly :(

EDIT I attempted to implement Matthew's suggestions (thanks Matthew!) but without success. The modified code looks like this:


    <div :id="'listItem'+index+1" :class="[selection != '' ? 
{available:selection==='Available',tentative:selection==='Tentative',busy:selection==='Busy',session:selection==='Session',unknown:selection==='Unknown'}
 : {available:value==='available', tentative:value==='tentative', busy:value==='busy', session:value==='session',unknown:value==='Unknown'}]" :key="index">
            <select id="availabilityOptions" v-model="value">
              <option>{{value}}</option>
              <option>Available</option>
              <option>Busy</option>
              <option>Tentative</option>
              <option>Session</option>
            </select>

Unfortunately, after these changes, a) no colors change at all now b) when adding a new player, all previous changes are erased.

Answer №1

The issue you are experiencing may stem from improper usage of the v-model directive. It is important to note that only one instance of v-model should be declared within the <select> element, not within each individual <option>

Refer to the documentation

Answer №2

After spending a considerable amount of time struggling with this issue, I opted to take a different approach. Thanks to the valuable insights provided by other users on this platform (which I will link below), I was able to find a solution for accessing individual DOM elements using a ref. Since $refs is an array, you must use bracket [] notation to access a specific element. When calling the updateColour() function, I passed both the event and index as parameters. It's worth noting that it should be ref, not :ref.

<div :id="'listItem'+index+1" ref="days" :class="[selection != '' ? {available:selection==='Available',tentative:selection==='Tentative',busy:selection==='Busy',session:selection==='Session',unknown:selection==='Unknown'} : {available:availability==='available', tentative:availability==='tentative', busy:availability==='busy', session:availability==='session',unknown:availability==='Unknown'}]" :key="index">
    <select id="availabilityOptions" @change="updateColour($event,index)" >

Subsequently, I could manipulate the specific element in the method and apply a class like so:

this.$refs.days[index].classList.remove("unknown","busy","tentative","session")
this.$refs.days[index].classList.add("available")

To avoid conflicts between classes, I removed all other classes before adding the new one.

You can view a newer version on CodePen, where I have kept the previous version for reference. This updated version now serves as the answer.

While this solution is still a work in progress and may have some flaws, it provides a way to change the style class of a specific element generated in a v-for list.

The following answers were particularly helpful:

This Stack Overflow post directed me to the Mozilla Developer Network documentation for classList.

Another answer on Stack Overflow clarified how to access the specific element, even though I ultimately did not use $el or .querySelector after discovering classList.

Lastly, this answer on Stack Overflow helped me grasp the concept of refs initially!

Special thanks to Matthew for his assistance :)

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

Utilizing ng-pattern in Angular to detect leading zeroes in alphanumeric input fields

Are you wondering how to identify a leading zero in an alphanumeric field using ng-pattern in angular? <body ng-app> <h1>Regex test</h1> <form name="myForm"> <input name="myNumberField" ng-model="myNumber" ng-pa ...

How can the checkers code be corrected due to a mistake?

Designed a simple game where the objective is to clear all the pieces by jumping over the checkers. However, encountering an error when attempting to remove the checker for the second time. Uncaught TypeError: Cannot read property 'theRow' of u ...

Is it possible to manually input values when printing a PDF instead of pulling them from the main HTML?

I am facing a challenge in adding a "Print PDF" option to my website because it is built using Ext.js, and therefore the code is not in HTML. Despite searching for ways to print a PDF from the site, all solutions I found involve using HTML. Is there any li ...

Having trouble installing the @mui/x-data-grid package in a React project

npm install @mui/x-data-grid encounters a problem that throws an error message: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" dat ...

Guide to changing an image on a canvas with KineticJS

I am currently working on developing a canvas that will display a hotel floor view. I have images stored in a database which I am drawing onto the canvas using x and y coordinates from the database as reference points. However, I want to add touch events t ...

JavaScript - An Efficient Method to Retrieve Data Imported from the Controller via Ajax

I am a beginner and I'm having trouble getting a list of objects called "Event" (OrderId, Date) from the MVC controller to JavaScript in the view. When I try to display the list as strings, it shows me "undefined". On the controller side, everything ...

Utilize JavaScript to assign a unique color to each category

I'm currently working on a JavaScript task My goal is to assign specific colors to different categories For example: if category name = x then color = blue if category name = y then color = red ... I attempted the following code, but it seems like ...

The expo-location feature is failing to accurately record and store all of the positions within the array

Incorporating expo-location in my react-native app, I utilize it to track the user's positions and store them in a redux object. While debugging the object reveals that all positions have been successfully inserted, upon retrieving this array, it turn ...

What is the best way to describe a type in TypeScript that serves as both an object and a function simultaneously?

Upon coming across this insightful answer to the query How does jQuery's $ function operate as both a function and an object?, I couldn't help but ponder. How can one define such a type in typescript? In traditional JS, the following code is per ...

Provide the user with an .ics file for easy access

Recently, I developed an HTML5 application that enables users to download calendar entries in iCal format. These iCals are generated using PHP. Up until now, my method involved creating the iCal file with PHP and saving it to the web server's hard dis ...

ng-bind-html is having trouble parsing the HTML correctly and binding it

Here is the code for my controller: myApp.controller('actionEditController', ['$scope', '$stateParams', '$sce',function ($scope, $stateParams, $sce) { $scope.table="<p>OOPSY</p>"; $sc ...

Utilize a form with a table layout to send all data to an IEnumerable Controller method

I'm experiencing an issue with a form containing data presented in a table structure @model IEnumerable<myType> @Html.AntiForgeryToken() @using (Ajax.BeginForm("Save", "NOC", null, ajaxopts, new { @encType = "multipart/form-data", @id = "myform ...

Uploading and previewing multiple images on a canvas

After successfully creating single upload for images and placing them on canvas as seen in http://jsfiddle.net/StJnY/, I am now looking to adapt the script for multiple image uploads. Here is how I plan to modify the script: JS : $(function () { $(&a ...

The method of connecting a Vue click event to Vue tables 2 (JSX)

When using Vue version 2 along with https://github.com/matfish2/vue-tables-2, I'm facing an issue binding the click event on JSX (specifically on templates->edit): var tableColumns = ['name', 'stock', 'sku', 'pri ...

There has been an issue with parsing the JSON file due to an invalid character found at

I keep encountering a parse error whenever I attempt to send a post request to the server. $.post("../php/user_handler.php", formData, function(data) { var result = JSON.parse(data); if(result.status === 'error') { ...

When making an Ajax request to another website, the response received is in HTML format instead of

I am attempting to retrieve an array by making an AJAX GET request to a URL. Below is my controller code, which is hosted locally at localhost:3000 def merchant_ids merchants = Merchant.where(id: params[:id]).pluck(:merchant_name, :id, :merchant_city, ...

Interactive chat feature with live updates utilizing jQuery's $.Ajax feature for desktop users

I came across a script for real-time chat using $.ajax jQuery, but it only refreshes my messages. Here's an example scenario: I type: Hello to You, and I see this message refreshed. You reply: Hey, in order to see your message, I have to manually refr ...

`Common issues when running NPM INSTALL in a Vue project`

I purchased a template and tried to install it on my PC, but I encountered an issue with the dependencies. When I run the NPM INSTALL command, I receive an error related to Python 2. About a year ago, I installed the template without any problems. However ...

Once I successfully deploy to Heroku, I encounter an application error. Despite using the JAWSdb add-on and MySQL locally, I am unable to establish a connection. What could be causing this issue?

The server configuration for handling standard express connections is set up in the following Server.js code: // Required dependencies var express = require('express'); var bodyParser = require('body-parser'); var methodOverride = ...

What is the best way to bring a module into an Angular project?

I have a project in Angular with an additional module created as an npm package. The structure of the module is as follows: --otherModule --other-module.module.ts --index.ts --package.json index.ts: export { OtherModule } from './other-module ...