Limit the selection to just one element in a v-for loop in VueJS

I am utilizing Vue v2

My goal is to change only the properties of the selected element. Specifically, when the response is marked after clicking, it should switch to red color with a text that reads 'Unmark'. Conversely, if the button is clicked again (which would then say 'Unmark'), it should switch to green color and the text should change to 'Mark'. Unfortunately, my current code applies these changes to every element within the v-for loop; I want it to happen only to the selected element.

I have considered using a Component to monitor any changes, but first, I would like to explore other potential solutions. Any assistance would be greatly appreciated.

Below is the code snippet:

<div class="search-results">
                <div class="activity-box-w" v-for="user in users">
                    <div class="box">
                      <div class="avatar" :style="{ 'background-image': 'url(' + user.customer.profile_picture + ')' }">
                      </div>
                      <div class="info">
                        <div class="role">
                          @{{ '@' + user.username }}
                        </div>
                        <div>
                            <div>
                                <p class="title">@{{ user.customer.name }} 
                                @{{user.customer.lastname}}
                                </p>
                            </div>

                        </div>
                      </div>
                      <div class="time">
                        <input type="button" class="btn btn-sm btn-primary" v-on:click.prevent="markUser(user)" v-model="text" 
                        v-bind:class="[{'green-border':notMarked}, {'red-border':marked}]" v-cloak v-if="!action"
                        :disabled="action"></input>
                    </div>
                </div>
            </div>

Below is the script section:

new Vue({
  el: '#engage-panel',
  data: {
    users: [],
    mark: {'id' : '', 'marks' : ''},
    text: 'Mark', //May change to Unmark later
    action: false,
    marked: null,
    notMarked: null,
  }, 
    methods:
{   
markUser: function(user){

      this.mark.id = user.id;
      this.action= true;

      Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name="csrf-token"]').attr('content');
      this.$http.put('/mark/user', this.mark).then(response => {

                  if(response.body === "marked")
                  {
                      this.mark.marks="true";
                      this.text = 'Unmark';
                      this.marked= true;
                      this.notMarked= false;
                      this.action= false;

                  }else{
                      this.mark.marks="false";                  
                      this.text = 'Mark';
                      this.marked= false;
                      this.notMarked= true;
                      this.action= false;
                  }

                }).catch(e => {

                    this.action= false;
                });
    }

}

Answer №1

To easily toggle a CSS class on click, you can utilize $event.target. Check out this fiddle for an example.

Alternatively, creating a status like marked = true/false for the user can simplify the process of binding classes:

<input :class="{ 'green-border': user.marked, 'red-border': !user.marked }">

Answer №2

The problem arises when

my code applies the change to every element
because each user in v-for="user in users" is using the same object to determine whether it is marked or not.

If your users data contains a property like status that stores the current status (e.g., unmarked, marked), the solution is simple - just switch to the next status when clicking the mark button.

If your users data lacks this property, you will need to create a dictionary where the clicked users are stored as keys and their corresponding statuses as values.

Here is a demonstration:

app = new Vue({
  el: "#app",
  data: {
    users1: [{'name':'abc', 'status':'none'},
            {'name':'xyz', 'status':'none'}],
    users2: [{'name':'abc'}, {'name':'xyz'}],
    selectedUsers: {}
  },
  methods: {
    getNextStatusBaseOnRoute: function (status) {
      if(status ==='marked') return 'marked'
      let routes = {'none':'unmark', 'unmark':'marked'}
      return routes[status]
    },
    markUser1: function (item) {
      item.status = this.getNextStatusBaseOnRoute(item.status)
    },
    markUser2: function (item) {
      let status = item.name in this.selectedUsers ? this.selectedUsers[item.name] : 'none'
      // remember to use vue.$set when adding new property to one object
      this.$set(this.selectedUsers, item.name, this.getNextStatusBaseOnRoute(status))
    }
  }
})
.marked {
  background-color:green;
}

.unmark {
  background-color:yellow;
}
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a8deddcde89a869d86999e">[email protected]</a>/dist/vue.js"></script>
<div id="app">
    <h2>Case 1: </h2>
    <div v-for="(item, index1) in users1" :key="'1'+index1">
      <span>{{item.name}}:</span><span :class="[item.status]">{{item.status}}</span><button @click="markUser1(item)">Mark</button>
    </div>
    <h2>Case 2: </h2>
    <div v-for="(item, index2) in users2" :key="'2'+index2">
      <span>{{item.name}}:</span><span :class="[item.name in selectedUsers ? selectedUsers[item.name] : 'none']">{{item.name in selectedUsers ? selectedUsers[item.name] : 'none'}}</span><button @click="markUser2(item)">Mark</button>
    </div>
</div>

Answer №3

Store the selected element's index in Vue3 for easy access.

<ul role="list" class="">
  <li class="relative" v-for="(image, index) of images" :class="selectedImage == index? 'border-indigo-500 border-2': 'border-transparent'" >
    <div @click="selectedImage = index" class="">
      <img :src="image" alt="" class="object-cover pointer-events-none group-hover:opacity-75">
    </div>
  </li>
</ul>

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

Swap out The div element with the html() method

I'm encountering an issue when trying to swap out a div element with ajax. My goal is to create a start/stop button functionality. The page displays a list of card elements, each with its own button, which are stored in separate html files. work_orde ...

Vue.js - The @oninput.native listener does not trigger in b-form-textarea components

I have a Vue application and I am trying to incorporate Facebook inspired buttons inline in a comment form. Previously, I had a plain JavaScript prototype that was functional. However, when integrating it into my Vue app, I encountered issues due to multip ...

Is it possible to send an email with an attachment that was generated as a blob within the browser?

Is there a way to attach a file created in the browser as a blob to an email, similar to embedding its direct path in the url for a local file? The file is generated as part of some javascript code that I am running. Thank you in advance! ...

Create a password variable while typing

Looking to avoid interference from browsers with autocomplete and password suggestions while maintaining the show/hide letters feature. The goal is to keep the password stored as a variable, regardless of whether the characters are shown or hidden. The is ...

Enhance and soften images using CSS with smooth responsiveness across all web browsers

When an image is clicked, it should zoom in and become the background of the page with a blurred effect. I attempted to achieve this using the following code... <style type="text/css"> body{ position: absolute; margin-left: 100px; right: 0; z-inde ...

Securing Communication with HTTPS in Express JS

After purchasing an AlphaSSL from a hosting provider, I received the following files: domain.csr.crt domain.interCert.crt domain.PKCS7Cert.crt domain.rootCert.crt domain.X509Cert.crt However, in order to enable HTTPS on Node.JS using Express, I am aware ...

grab the content from a text editor and insert it into a div element

Currently, I am trying to extract text from my content editable div and place it in another div (similar to the one seen on stack overflow). However, I am encountering a frustrating issue. 1. My content div seems to be lagging behind. When I type in my ed ...

Express.js app issue: post id assigns category name instead

Currently, I am in the process of developing a blogging application using Express, EJS, and MongoDB. To view the GitHub repository for this project, please click on this link. The posts within my application are organized into different categories, each r ...

Animate the Bootstrap carousel from top to bottom instead of the traditional left to right movement

Is there an option available in the bootstrap carousel to animate it from top to bottom and bottom to top, rather than from right to left and left to right? jsFiddle link <div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval=" ...

Transitioning images smoothly and responsively with jQuery, creating a beautiful

Hey there! I'm looking for some help with transforming this jQuery effect. Instead of having fixed sized images, I want to set the size in percentage (width:100%; height:auto) so they can be responsive. Any creative ideas or suggestions? <scri ...

Prevent automatic scrolling by clicking when you reach the bottom

In order to replicate the issue I am experiencing, please click on the down button four times, and then click on the up button. You will observe that you need to click the up button one extra time for it to function properly. How can I detect when it has r ...

Attempting to create a TypeScript + React component that can accept multiple types of props, but running into the issue where only the common prop is accessible

I am looking to create a component named Foo that can accept two different sets of props: Foo({a: 'a'}) Foo({a: 'a', b: 'b', c:'c'}) The prop {a: 'a'} is mandatory. These scenarios should be considered i ...

Using a React component to trigger an action when the Enter key

I have a react component that needs to respond to the "Enter" key press event. class MyComponent extends Component { componentDidMount() { console.log('componentDidMount'); document.removeEventListener('keypress', t ...

Converting Arrays into Objects with Multiple Dimensions

I have been attempting to transform this complex array into an object. However, I am facing an issue where only the second part of the array is being saved in the object, while the first part is missing. Is there a way to ensure that the entire array gets ...

Ways to automatically close the external window upon logging out in Angular 12

I have successfully created an external window in my Angular application. Everything is working as expected, but I am facing an issue when trying to automatically close the external window upon user logout. Although I have written the code below and it wo ...

What is the reason for the countdown number's color remaining the same even after it reaches a specific time threshold?

Creating a simple countdown for sports was my idea, but now I'm stuck on the "changeColor" part that I don't have enough knowledge about. The countdown is functioning perfectly, but customizing the colors and adding CSS animations seems challeng ...

What's the best way to unpack the gzip data that Ajax sends to JavaScript?

Hello there! I've encountered an issue: PHP is sending compressed data using gzdeflate(): $string=gzdeflate($string,9); echo $string; In the browser, pako.js has been included and the following code is executed: var rsp=rst.responseText; rsp=pako.in ...

What is the reason behind the code breaking when a newline is added between `return` and `(`?

After investigating my query, it seems that a peculiar issue arises in the code where setState fires and render method gets hit, but nothing rerenders The code functions correctly when there is no newline between the return statement and opening parenthes ...

Oops! The Route post function is missing some necessary callback functions, resulting in an undefined object error

I need to verify if a user has admin privileges. Every time I try calling the verifyAdminUser function from my router, I encounter the following error: Error: Route.post() requires callback functions but got a [object Undefined] at Route.(anonymous func ...

Error: Value of incoming scope in Angular Directive is not defined

When working in html, I passed an object into a directive like this: <lcd-code ldcCode="{{ detail.program.ldcCode }}"></lcd-code> The value of detail.program.ldcCode is "PSIH"... However, in the Directive, it is showing up as undefined: var ...