How can I apply a class to a list item when clicked using Vue.js and a template component generated by v-for loop?

I'm struggling to add an active class to a list item in a template component when it's clicked, making sure that only one item can have the class at a time.

I've attempted different solutions such as passing a new data object on click and referencing it, but nothing seems to work. Even the example provided in the official documentation doesn't give me any clues on why it's not working.

Vue.component('delivery-options', {
      props: ['deliveries'],
      template: '<li><p><strong>{{ deliveries.price }}</strong>{{ deliveries.title }}</p><p>{{ deliveries.desc }}</p></li>'
    })
    Vue.component('ledger', {
      props: ['values'],
      template: '<li><p>{{ values.title }}<span>{{ values.price }}</span></p></li>'
    })
    var checkout = new Vue({
      el: '#checkout-app',
      data: {
        deliveryList: [
          { id: 0, price: '£3.99 ', title: 'Home delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: 'Free ', title: 'Store collection', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99 ', title: 'Precise delivery', desc: 'Lorem ipsum dolor sit amet.' }
        ],
        valuesList: [
          { id: 0, price: '£1233.99', title: 'Order value', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: '£3.99', title: 'Delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99', title: 'Total', desc: 'Your total including delivery.' }
        ]
      }
    })
ul {
  padding: 0;
}

ul li {
  list-style-type: none;
}

.delivery-options li {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.ledger {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}
<script src="https://unpkg.com/vue"></script>
<div id="checkout-app">
    <ul class="delivery-options">
      <delivery-options
        v-for="option in deliveryList"
        v-bind:deliveries="option"
        v-bind:key="option.id">
      </delivery-options>
    </ul>
    <ul class="ledger">
      <ledger
        v-for="value in valuesList"
        v-bind:values="value"
        v-bind:key="value.id">
      </ledger>
    </ul>
  </div>

Answer №1

To achieve this functionality, you can follow these steps:

console.clear()

Vue.component('delivery-options', {
      props: ['deliveries', "isActive"],
      template: `<li @click="$emit('set-active', deliveries)" :class="{active: isActive}"><p><strong>{{ deliveries.price }}</strong>{{ deliveries.title }}</p><p>{{ deliveries.desc }}</p></li>`
    })
    Vue.component('ledger', {
      props: ['values'],
      template: '<li><p>{{ values.title }}<span>{{ values.price }}</span></p></li>'
    })
    var checkout = new Vue({
      el: '#checkout-app',
      data: {
        activeDelivery: null,
        deliveryList: [
          { id: 0, price: '£3.99 ', title: 'Home delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: 'Free ', title: 'Store collection', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99 ', title: 'Precise delivery', desc: 'Lorem ipsum dolor sit amet.' }
        ],
        valuesList: [
          { id: 0, price: '£1233.99', title: 'Order value', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 1, price: '£3.99', title: 'Delivery', desc: 'Lorem ipsum dolor sit amet.' },
          { id: 2, price: '£5.99', title: 'Total', desc: 'Your total including delivery.' }
        ]
      },
    })
ul {
  padding: 0;
}

ul li {
  list-style-type: none;
}

.delivery-options li {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.ledger {
  padding: 1rem;
  margin: 1rem;
  border-radius: 3px;
  border: 1px solid grey;
}

.active {
  color: red
}
<script src="https://unpkg.com/vue"></script>
<div id="checkout-app">
    <ul class="delivery-options">
      <delivery-options
        v-for="option in deliveryList"
        v-bind:deliveries="option"
        v-bind:key="option.id"
        v-bind:is-active="option === activeDelivery"
        v-on:set-active="v => activeDelivery = v">
      </delivery-options>
    </ul>
    <ul class="ledger">
      <ledger
        v-for="value in valuesList"
        v-bind:values="value"
        v-bind:key="value.id">
      </ledger>
    </ul>
  </div>

In essence, the key is to maintain the active delivery state using a data property and apply the appropriate class within the component based on whether it is active or not. To update the active delivery on click, the component must emit an event to notify the parent component of the selected delivery.

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

Exporting JSON data to an Excel file using an array of objects with embedded arrays

I am currently developing a fitness application that allows users to create workout routines and download them as an excel file. The data is structured as an array of objects, with each object representing a workout date and containing details of the exerc ...

NodeJS/express: server became unresponsive after running for some time

Initially, my service using express and webpack ran smoothly. However, I started encountering an issue where the server would hang with no message code being received, as shown in the server message screenshot (server message screenshot). This problem kept ...

Issues are arising with the .mouseover functionality within this particular code snippet

Learning Javascript has been a challenge for me so far. I tried following a tutorial, but the result I got wasn't what I expected based on the video. I'm wondering why that is and how I can fix it. I'm aiming to make a box appear suddenly w ...

Having issues binding a CSS class after committing in the created function with Vue.JS and VueX while using Server-Side Rendering (SS

I recently set up a new Vuex variable with a mutation. I successfully changed the variable in the "created" Vue.js function within the component and received a value of "true". However, when trying to bind a class in a parent component, it did not work pro ...

Is there a different option available in place of the JavaScript confirm function?

I developed an application where I heavily utilized the javascript confirm function. confirm("Do you want to proceed"); However, I am not satisfied with the default appearance of the confirm dialog and would like to implement a customized version with be ...

What is the procedure for utilizing the comparator to arrange items according to various attributes?

I am trying to find a way to arrange my models in a collection based on their required flag and then alphabetically by their value. This is what my current code looks like: var myModel = Backbone.Model.extend({ defaults: { required: true, ...

The functionality of updating the logo in the browser tabs is not functioning as expected in Vue.js 3

This is the code from my index.html: <!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE ...

Employing jq to transfer the value of a child property to the parent dictionary

My TopoJSON file contains multiple geometries, structured as follows: { "type": "Topology", "objects": { "delegaciones": { "geometries": [ { "properties": { "name": "Tlalpan", "municip": "012", ...

Unable to modify a variable within a request

Having trouble updating a variable within a request? It seems like the variable doesn't change when it should. const request = require("request"); var all = JSON.parse(body); var steamplayer = all['response']['players']['play ...

Ways to determine the overall cost of a shopping cart using Vuejs Vuex

Running a business requires managing various aspects, including tracking the inventory. In my store, I have an array called basketContents that contains items with their respective quantities and prices. An example of how it looks is: state: { basketConte ...

Issue with PrimeNG Calendar not updating date value within modal

While using the PrimeNG Calendar control, I encountered an issue. Even though I am able to select and store dates, when I try to fetch dates from a database and update the Modal, I receive the following error message: <p-calendar [(ngModel)]="bi ...

Jquery Triggers Failing to Work Following Ajax Request

I have worked on 2 PHP pages, called "booking.php" and "fetch_book_time.php". Within my booking.php (where the jquery trigger is) <?php include ("conn.php"); include ("functions.php"); ?> $(document).ready(function(){ $(".form-group"). ...

The XMLHttpRequest function successfully logs data in the console, but does not return the data within the function itself

I find it puzzling that the console.log statement at the end of the code snippet displays the data as expected, while the return optiondata line does not. function populate_selectbox() { var ajaxRequest; try { // Opera 8.0+, Firefox, S ...

I am attempting to utilize the fetch API method to initialize the store's state, but for some reason, it is not functioning properly

Within my store.js file, I have a state called user_data, with its initial method set to fetch_user_data: export default new Vuex.Store({ state: { user_data: util.fetch_user_data('username') ... } located in the util.js file: util. ...

Utilizing i18n for moment formatting techniques

As I switch from moment to date-fns, I came across this code that involves moment, which I don't quite understand. However, I do comprehend the map function. this.events[0].dates.map(date => moment(date).format(this.$i18n.locale)) I set up an e ...

Exploring the Differences Between Arrays in JavaScript

I am currently tackling the task of comparing arrays in JavaScript, specifically within node.js. Here are the two arrays I am working with: Array 1: [16,31,34,22,64,57,24,74,7,39,72,6,42,41,40,30,10,55,23,32,11,37,4,3,2,52,1,17,50,56,60,65,48,43,58,28,3 ...

Is there a way to overlay a 'secret' grid on top of a canvas that features a background image?

I am currently working on developing an HTML/JS turn-based game, where I have implemented a canvas element using JavaScript. The canvas has a repeated background image to resemble a 10x10 squared board. However, I want to overlay a grid on top of it so tha ...

Issue: Access to sdcard/hello.mp3 file denied due to permission error (EACCES)

While testing the "react-native-audio-recorder-player": "^3.5.3" on Android 11 & 12 with targetSDKversion 31, I encountered the error message Error: sdcard/sound.mp3: open failed: EACCES (Permission denied). Numerous suggested solut ...

An error was discovered: [$injector:unpr] The provider aProvider is not recognized <- a

While working on my development machine, I encountered no issues. However, upon loading the same form onto my production server, I encountered an error: Uncaught Error: [$injector:unpr] Unknown provider: aProvider <- a I found that removing the followi ...

What is the process for incorporating a custom type into Next.js's NextApiRequest object?

I have implemented a middleware to verify JWT tokens for API requests in Next.js. The middleware is written in TypeScript, but I encountered a type error. Below is my code snippet: import { verifyJwtToken } from "../utils/verifyJwtToken.js"; imp ...