Using Vue to cycle through an array of objects, and emphasize the chosen item by clicking on it

I have to display an array of objects in the DOM by using map method. Each item has a @click event listener where I want to highlight it with a CSS class 'hover'. The desired functionality is to mimic a menu system where only the clicked item should be highlighted, not all items at once.

Currently, all items are getting highlighted when clicked which is not the intended behavior. I've used console.log to track the clicked item but haven't been able to figure out how to highlight only that specific item instead of all items on the list.

<template>
<div>
    <div>
        <h1>Dragonball</h1>
    </div>
    <div>
        <ul>
            <li v-for="(dragonBallFighters, index) of dragonBallFighter" @click="toggleClass(dragonBallFighters.id)" :key=dragonBallFighters.id :class="{hover: active}">
                <div class="dragonball-container">
                    <div class="dragonball-stats">
                    <h1>{{index}}, {{dragonBallFighters.name}}</h1>
                    <p>{{dragonBallFighters.race}}</p>
                    <p>{{dragonBallFighters.specialAttack}}</p>
                </div>
                <div class="dragonball-image">
                    <img :src="dragonBallFighters.img" :alt="dragonBallFighters.name" />
                </div>
                </div>
            </li>
        </ul>
    </div>
</div>
</template>

<script>
export default {
  data() {
    return {
      active: false,
      dragonBallFighter: [
        // List of Dragon Ball fighters
      ]
    };
  },
  methods: {
    toggleClass(id) {
      console.log('Clicked ' + id);

      const currentState = this.active;
      this.active = !currentState;
      //   this.selectedItemIndex = id;

      if (this.selectedItemIndex === id) {
        this.active === true;
      } else if (this.selectedItemIndex === !id) {
        this.active === false;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.dragonball-container {
  cursor: pointer;
  display: grid;
  padding: 20px;
  grid-template-columns: 1fr 1fr;
  //background: #666;
  border: 2px solid #666;
  grid-gap: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  -webkit-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  -moz-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
}

.dragonball-image img {
  display: grid;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: 300px;
  border-radius: 100%;
}

ul li {
  list-style: none;
}
.hover {
  background: rgb(244, 244, 244);
  border-radius: 10px;
}
</style>

Answer №1

I personally like to approach this by assigning a new key to each fighter and utilizing that key in the v-for loop. All that needs to be done in the markup is to update the :class value to utilize the active key from the fighters within the v-for loop.

   <li
      v-for="(fighter, index) of fighters"
      @click="toggleActive(fighter.id)"
      :key=fighter.id
      :class="{active: fighter.active}"
   >
    <div class="fighter-container">
      <div class="fighter-details">
        <h1>{{index}}, {{fighter.name}}</h1>
        <p>{{fighter.species}}</p>
        <p>{{fighter.specialMove}}</p>
      </div>
      <div class="fighter-image">
        <img :src="fighter.img" :alt="fighter.name" />
      </div>
    </div>
  </li>

In the JavaScript section, we use Vue.set() to inform the DOM about the addition of a key that is not part of the original object being iterated over by v-for. This allows Vue to correctly update the DOM when changing the 'active' status of a fighter.

toggleActive(id) {
  let allFighters = this.fighters;
  let clickedFighter = allFighters.find(e => e.id === id);
  allFighters = allFighters.map(e => Vue.set(e, 'active', false));
  Vue.set(clickedFighter, 'active', !clickedFighter.active);
}

See live example

The method I use to toggle the active class is simply by using !fighter.active. When the fighter's 'active' property is true, !true will result in false, and vice versa.

Furthermore, I recommend renaming the object representing fighters to fighters for clarity. This adjustment aligns better with the v-for syntax, making it more intuitive as "

<v-for="fighter in fighters"
" can be interpreted as:

for each fighter in the fighters object.

Currently, you are indirectly implying:

for each fighters in the fighter object

which may cause confusion in understanding;)

Answer №2

Assign the attribute "active" to every DragonBall fighter and activate it upon clicking, deactivating the others.

The principle of Vue involves manipulating data and allowing Vue to manage the user interface :)

Alternatively

Change the name "active" to activeID, assign the clicked item's ID to activeID, and enable hover effects only if activeID matches item.id

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

React-Tooltip trimming

Currently, I am facing a dilemma that requires some resolution. The issue at hand is related to the placement of React-Tooltip within the List element. Whenever it's positioned there, it gets clipped. On the other hand, placing it at the bottom isn&a ...

Tips for updating the background color of a specific row

I have a piece of code that I am trying to modify with a specific condition. If {row.BB} is less than or equal to 100, I want to change the background color of the row with this value to red. Can someone help me achieve this? The code is linked to a data ...

Leverage the power of Laravel and Vue Sanctum to implement authorization in your application

Currently, I am working on a laravel + vue project and implementing sanctum for authentication purposes. However, in addition to authentication, I also need authorization functionality in my project. I have been searching for a solution similar to (spate l ...

When an import is included, a Typescript self-executing function will fail to run

Looking at this Typescript code: (()=> { console.log('called boot'); // 'called boot' })(); The resulting JavaScript is: (function () { console.log('called boot'); })(); define("StockMarketService", ["require", "exp ...

The new FormData(form) method unexpectedly returns an empty object

In this scenario, I am aiming to retrieve key-value pairs. The form on my page looks like this: <form id="myForm" name="myForm"> <label for="username">Enter name:</label> <input type="text" id="username" name="username"> ...

The functionality for selecting text in multiple dropdown menus using the .on method is currently limited to the first dropdown

Having trouble selecting an li element from a Bootstrap dropdown and displaying it in the dropdown box? I'm facing an issue where only the text from the first dropdown changes and the event for the second dropdown doesn't work. <div class="dr ...

Putting off the execution of a setTimeout()

I'm encountering difficulties with a piece of asynchronous JavaScript code designed to fetch values from a database using ajax. The objective is to reload a page once a list has been populated. To achieve this, I attempted to embed the following code ...

Vue: Conditionally importing SCSS when a component is instantiated

My goal is to import Material SCSS exclusively for my Admin component. While this setup works smoothly during local development, the issue arises when I deploy my site to Firebase hosting - the Material styles start affecting not just my Admin component, ...

Validate the Vuetify data table by retrieving data with a fetch request

I have integrated a v-data-table into my project to display data pulled from the backend. The data comes in the form of item IDs. How can I efficiently match the incoming IDs with the object IDs in the categories and show the corresponding category names i ...

Is it achievable to dynamically generate new pages on initial load in NextJS?

Right now, I am utilizing getStaticProps and getStaticPaths to pre-render a specific number of articles before my website goes live. This method works effectively, but if a new article is created and displayed on the front page while the site is still acti ...

Preserving Previous Values in Vuetify Select

Experience a unique way of handling Vueitfy selections with this code snippet: <v-select label="..." autocomplete append-icon="search" :items="plots" item-value="id" item-text="plotHeader" v-model="selectedPlot" v-on:change="loadPlotInforma ...

How can serial numbers be sorted using a JavaScript If Statement based on 2 criteria?

I'm currently enrolled in a JavaScript coding course where I am tackling a task involving validating serial numbers. The requirement is to check if a serial number is valid and then add it to an array to store all the valid serial numbers. The criteri ...

The AJAX event is failing to send data

When using two ajax calls, the first one populates a dropdown box successfully. However, the second ajax call utilizes a change event function to list product details with images whenever a dynamically populated item from the dropdown is clicked. In the c ...

Error Handling with Firebase Cloud Firestore and State Management in Vue using Vuex (firebase.firestore.QuerySnapshot)

Upon examining the code, I noticed an issue with docChanges. It seems to be a function, but when I try to use docChanges().doc.data().userId, I encounter the error message: store.js?3bf3:21 Uncaught TypeError: Cannot read property 'doc' of undefi ...

Issue with Bootstrap side navbar not collapsing when clicked on a link

Currently, I'm working on creating a website for a friend. While I used to have some experience with coding in the past, it has been a while and I am a bit rusty. This time around, I decided to use bootstrap for the project. However, I'm struggli ...

What is the process for displaying user input on the console?

How can I ensure that the server is receiving user input? What steps should I take to print this input to the console? Currently, the console.log statement only displays "About to create new room", but I require the user input as well. Client-Side: // C ...

Creating a dynamic CSS height for a div in Angular CLI V12 with variables

Exploring Angular development is a new venture for me, and I could use some guidance on how to achieve a variable CSS height in Angular CLI V12. Let me simplify my query by presenting it as follows: I have three boxes displayed below. Visual representatio ...

The problem of interpreting JSON using the JavaScript eval() function

Here is the JSON string provided : { "name":"Ruby on Rails Baseball Jersey", "price":"19.99", "id":"1025786064", "image":"" }, { "name":"Ruby on Rails Baseball Jersey", "price":"19.99", "id":"1025786064", "image":"" }, { "name ...

Finding the Right Path: Unraveling the Ember Way

Within my application, I have a requirement for the user to refrain from using the browser's back button once they reach the last page. To address this, I have implemented a method to update the existing url with the current page's url, thereby e ...

Exploring Material UI: Customizing the styling of components within TablePagination

Is it possible to customize the styling of buttons within the actions panel of the TablePagination component? import { withStyles } from '@material-ui/core'; import MuiTablePagination from '@material-ui/core/TablePagination'; const st ...