Troubleshooting Vue v-for loop triggering click events on multiple items simultaneously

After conducting a thorough search, I haven't found a suitable answer for my issue. The problem I am facing involves a v-for loop with buttons on each item, using VueClipboard2 to copy text. Whenever a button is clicked, some CSS changes are applied to indicate the copied item. However, the issue arises when clicking on one button affects all other items and produces the same effect.

I am looking to restrict the click event to the specific item being clicked.

Below is the code snippet:

<template>
    <div class="form" id="shorten">
        <form class="" @submit.prevent="shortener($event, value)">
            <div>
                <div class="form__shortener">
                    <input
                        class="form-input"
                        type="url"
                        name="link"
                        id="link"
                        placeholder="shorten a url here"
                        aria-label="input a url"
                        v-model="value"
                    />
                    <button class="form-btn btn">
                        {{ buttonText }}
                        <p v-if="loading" class="loading"></p>
                    </button>
                </div>
                <SlideXLeftTransition :delay="100">
                    <p v-if="error" class="error">Please enter a valid link</p>
                </SlideXLeftTransition>
            </div>
        </form>
        <SlideYUpTransition group>
            <div v-for="(link, index) in links" :key="index" class="form__links">
                <p class="form__links-main">
                    {{ link.mainUrl }}
                </p>
                <div class="center form__links-copy">
                    <p>
                        <a :href="link.shortenedUrl" class="form__links-copy-link no-decoration">{{ link.shortenedUrl }}</a>
                    </p>
                    <button
                        class="form__links-copyBtn btn"
                        :class="[copied === true ? 'copied' : '']"
                        v-clipboard:copy="link.shortenedUrl"
                        v-clipboard:success="onCopy"
                        v-clipboard:error="onError"
                    >
                        <span v-if="!loading && !copied">Copy</span>
                        <span v-if="copied">Copied!</span>
                    </button>
                </div>
            </div>
        </SlideYUpTransition>
    </div>
</template>

<script>
import { required, minLength } from 'vuelidate/lib/validators';
import { SlideYUpTransition, SlideXLeftTransition } from 'vue2-transitions';

import axios from 'axios';

export default {
    data() {
        return {
            value: '',
            links: [],
            message: '',
            error: false,
            loading: false,
            buttonText: 'Shorten it!',
            shortenedUrl: '',
            copied: false,
        };
    },
    validations: {
        value: {
            required,
            minLength: minLength(1),
        },
    },
    methods: {
        async shortener(event, value) {
            this.$v.$touch();
            if (this.$v.$invalid) {
                this.showError();
            } else {
                try {
                    this.loading = true;
                    this.buttonText = 'Loading';
                    const request = await axios.post('https://rel.ink/api/links/', { url: value });
                    this.loading = false;
                    this.buttonText = 'Shortened!';
                    setTimeout(() => {
                        this.buttonText = 'Shorten it!';
                    }, 1200);
                    this.shortenedUrl = `https://rel.ink/${request.data.hashid}`;
                    const mainUrl = request.data.url.length <= 20 ? request.data.url : `${request.data.url.slice(0, 30)}...`;
                    this.links.push({
                        shortenedUrl: `https://rel.ink/${request.data.hashid}`,
                        mainUrl,
                    });
                    localStorage.setItem('links', JSON.stringify(this.links));
                } catch (error) {
                    this.showError();
                    console.log(error);
                }
            }
        },
        onCopy() {
            this.copied = true;
            setTimeout(() => {
                this.copied = false;
            }, 2500);
        },
        showError() {
            this.error = true;
            setTimeout(() => {
                this.error = false;
            }, 2000);
        },
        onError() {
            alert('Sorry, there was an error copying that link. please reload!');
        },
        getLinks() {
            if (localStorage.getItem('links')) this.links = JSON.parse(localStorage.getItem('links'));
        },
    },
    components: {
        SlideYUpTransition,
        SlideXLeftTransition,
    },
    mounted() {
        this.getLinks();
    },
};
</script>

Your assistance would be greatly appreciated.

View the live link here:

To replicate the issue, shorten two URLs and click the copy button on one of them. This action triggers all other item's buttons as well.

Thank you for your help.

Answer №1

The root cause of your issue lies in the fact that every time you click on a copy button, the variable :class="[copied === true ? 'copied' : '']" is changed, resulting in the same class being applied to all instances.

To resolve this issue, it is recommended that you associate the copied status with each individual link. This can be achieved by creating each link as an object.

links = [{ link: 'url...', copied: false}, {}, ...].

Subsequently, ensure to verify the copied status for each link independently.

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

Unable to navigate using react-router after logging out without a page refresh

In my logout approach, everything seems to work fine - there are no errors in the console, localHistory is cleared successfully, but for some reason it cannot navigate to the login page without refreshing the current page. const handleLogout = () => { ...

How can I limit the input of string values from a Node Express request query?

export type TodoRequest = { order?: 'asc' | 'desc' | undefined; } export const parseTodoRequest = (requestData: ParsedQs): TodoRequest => { return { order: requestData.order as 'asc' | 'desc' | u ...

Tips for eliminating duplicate values from an array of objects in JavaScript

I am working with an array of objects where my goal is to remove duplicate values from the values array. I would like the final result to be [{name:'test1', values:['35,5', '35,2','35,3']}, {name:'test2', v ...

The behavior of Elementor lightbox buttons upon being clicked

When using Android, I've noticed that the lightbox briefly displays a semitransparent cyan bar on the left and right buttons when they are pressed. Is there a way to control or prevent this behavior? Any suggestions would be appreciated! Thanks in adv ...

How come submitting a form without refreshing does not update the database with new values?

I'm encountering an issue with my form and script that is supposed to connect to the operation.php class. Despite having everything set up correctly, the data is not being added to the database and the page does not refresh. I'm perplexed as to ...

The Google Maps geocoding service fails to provide accurate location information

I am currently attempting to utilize the Google Maps Geocoding API within my JavaScript code. Below is the snippet I have written: var geocoder = new google.maps.Geocoder(); function geocodeAddress() { var address = document.getElementById("address").v ...

Having difficulty converting the string data to HTML using JavaScript in a Node.js Express application

In my app.js file, I will be sending data to an EJS file. app.get('/', function (req, res){ Blog.find({}, function(err, fountItems){ Blog.insertMany(defaultBlog, function(err){ }) } res.render( ...

Access the JavaScript variable in a webview and store it in an Android variable

I have been attempting to retrieve a variable from a webview, but I am only able to make modifications like this: browser.loadUrl("javascript:var x = document.getElementById('login').value = 'something';"); However, I need to be able ...

Unable to connect beyond the local network using Socket.io

server.js import { Server } from "socket.io"; const io = new Server(8000); io.on("connect", (socket) => { console.log(`connect ${socket.id}`); socket.on("ping", (cb) => { console.log("ping"); ...

issue with integrating promise in angular 4

I'm currently learning about promises and how to implement them in Angular. I have written the following code in StackBlitz. My goal is to display the array whenever it contains a value by using promises in Angular. This is my HTML code: <h2>A ...

Discovering ways to access deeply nested JSON data in Vue JS

i am dealing with JSON data that includes payment information. I am facing issues retrieving the paid_amount and date for both cash_payment and installment_payment. { "response": [ { "status": "sold", "price": "1000 ...

Difficulty Establishing a Connection with SQL Server Using TypeORM

My local machine is running an SQL Server instance, but I'm encountering an error when trying to connect a database from TypeORM. The error message reads: originalError: ConnectionError: Failed to connect to localhost:1433 - Could not connect (seque ...

The new Date function is malfunctioning on Firefox

Could you please explain why this particular function is not functioning correctly in Firefox (V 34 latest)? It appears to be working successfully on all other browsers, but 'DatePosted' is displaying as Invalid Date. Do you have any insights on ...

Experience the advanced NgPrime p-dropdown template with templating, filtering, and a clear icon that collapses when wrapped within a form element

Check out this link for a demo Whenever I enclose the code below in a </form> element, the drop-down menu collapses. <h5>Advanced with Templating, Filtering and Clear Icon</h5> <p-dropdown [options]="countries" [(ngModel)]=& ...

What is the method used by React or Next to prevent the <a> tag from refreshing the page while still loading content?

I'm currently diving into the world of NextJS and utilizing the Link component from the 'next/link' package. One thing that has been puzzling me is how the <Link> component ultimately renders an <a> tag with a href='/tosomew ...

Having trouble utilizing Reactjs Pagination to navigate through the data

I'm currently working on implementing pagination for a list of 50 records, but I'm encountering an issue. Even though I have the code below, it only displays 10 records and I'm unaware of how to show the next set of 10 records until all 50 a ...

Building a TypeScript Rest API with efficient routing, controllers, and classes for seamless management

I have been working on transitioning a Node project to TypeScript using Express and CoreModel. In my original setup, the structure looked like this: to manage users accountRouter <- accountController <- User (Class) <- CoreModel (parent Class o ...

The file always fails the Regex test in Node.js

I am dealing with a log file that contains lines structured like this: [Thu Mar 30 2017 11:24:51 GMT+0100 (WEST)] {"serial":"CA-2M-1107619","type":"iface","body":{"action":"up","device":"tun_man","ip":"127.255.0.10","ip6":"2016:900d:c0de::1001"} My goal ...

I am unable to achieve negative X degree rotation of the image while using mousemove to rotate it

I need assistance with moving a picture in 3D. I want the offsetX of the mouse to be positive when it's past half of the picture, and negative otherwise. How can I achieve this effect for rotation degrees? This is what I have tried: $('#img ...

Transferring PHP and JavaScript variables via AJAX to PHP page and storing in MySQL database table

After searching through numerous similar questions, I still haven't found the exact answer I need. I have a set of js variables that are sent via ajax to a location.php file, where they will be inserted into a mysql table. The current ajax call looks ...