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

Switching Primary Menu Selection When Scrolling Through Various Menu Options

I need help with changing the active class of links on my single page scrolling website. I found some useful code snippets for smooth scrolling and updating the active class on scroll or click events: $(document).ready(function () { $(document).on(" ...

I have to ensure that a plugin is only loaded once its dependency has been loaded with RequireJS

Currently, I am utilizing the jquery.validationEngine.js plugin and facing an issue. It seems that jqueryValidateEnglish is unable to function properly unless jqueryValidateEngine is loaded beforehand. In my code for jquery.wrapped.validationEnglish2.js, ...

What is the best way to eliminate YouTube branding from a video embedded in a website?

I am currently utilizing an <iframe width="550" height="314" src="https://www.youtube.com/embed/vidid?modestbranding=1&amp;rel=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe> This setup removes the "YouTube" logo from the ...

deleting a aircraft upon the addition of another in three.js

I am striving to implement a button that toggles between different terrain-generating functions and removes the previous terrain. The current issue I am facing is that the planes stack on top of each other. You can see an image of the problem here. There ...

What are the best practices for successfully launching a Vue + Apollo Server & Client application on Heroku?

Recently, I delved into the world of Vue.js paired with Graphql. After some learning and experimentation, I decided to scaffold a project using vue ui (vue cli 3) and incorporated vue-cli-plugin-apollo for both the client and server. My current project str ...

How can the value attribute be obtained from the click class?

$(document).on('click','.edit', function(){ var appid = $(this).getAttribute('value'); I am trying to figure out how to save the value of the "value" attribute for an image with the edit class. Can anyone help me with thi ...

Tips on updating Angular data model when a static HTML element changes

Currently, I am utilizing the editable-table jQuery plugin to enable editing in a table. This tool is simple to implement, lightweight, and highly efficient. The markup structure for this task looks like this: <tr ng-repeat="o in orders"> <td ...

The handler provided to Boost::asio::async_read_until is never triggered

I am attempting to establish a connection between two computers on a local network. One is using a slightly modified version of the Boost Asio C++ TCP asynchronous server sample, while the other is running NodeJS. tcp_client.js : var net = require(' ...

Only carry out a redirect to the specified page if the successRedirect is present in the passport.authenticate function

Encountering some difficulties with a Node Express app. After removing the successRedirect property in the auth method by passport, it fails to redirect. The below code does not redirect to the desired page when the successRedirect is removed and replaced ...

What is the process for implementing a Content Security Policy to enable the loading of external JS files from a CDN in ExpressJS?

When working with ExpressJS, the HTML file is loaded in the following manner: app.use(express.static(__dirname + '/src/templates/')); Within the HTML file, here is an example of a meta tag containing Content Security Policy: <meta http-equiv= ...

typescript: best practices for typing key and value parameters in the forEach loop of Object.entries()

I have a specific object with key/value pairs that I need to iterate over using the entries() method of Object followed by a forEach() method of Array. However, I'm struggling to understand how to avoid a typescript error in this situation: type objTy ...

Guide to implement a confirmation box in PHP

I recently set up a Joomla article and integrated the Sourcerer Joomla extension to include JavaScript and PHP in my project. Currently, I am developing a course purchase site where users can buy courses from owners and credits are deducted upon every purc ...

Improper menu alignment following a MenuItem hover event within Material-UI

When a MenuItem is hovered over, the position of the Menu container should remain unchanged. [x] The issue persists in the most recent release. However, downgrading MUI to v4.5.0 results in the expected behavior. Current Behavior ...

Tips for implementing async await properly within a function array that contains two functions for utilizing Promise.all in Vue

I am facing an issue with using await at the specified location in 1.vue file. Whenever I try to use await, it throws an error stating Unexpected reserved word 'await'. How can I modify async useFunctionToAllServers() to execute sequentially afte ...

Tips on concealing a div until the value of a specific field surpasses zero

In order to ensure that users focus on the first section of the form before proceeding, I plan to hide the last section until a specific field has a value greater than zero. Check out my HTML code below: <div class="fieldcontainer"> <label>E- ...

AngularJS using the ng-controller directive

I am presenting the following HTML code excerpt... <!DOCTYPE html> <html lang="en-US" ng-app> <head> <title>priklad00007</title> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angula ...

custom vertical tab label text not aligning to the right in material-ui with textAlign

I am struggling with customizing the tabs in material-ui to display them vertically. I also want the text labels of these tabs to align to the right for a more cohesive look. Despite trying various styling options, I have not been successful in achieving t ...

Guide to smoothly scroll to a specific Label using GSAP's scrollTrigger and scrubbing within a Timeline

Currently facing an issue with a scrollTrigger Timeline where I need a button to scroll to a specific position. I attempted using seek but it did not work, and even the ScrollTo plugin lacks support for this functionality. The Timeline created using gsap ...

Trouble with importing React JSX from a separate file when working with Typescript

This problem bears some resemblance to How to import React JSX correctly from a separate file in Typescript 1.6. Everything seems to be working smoothly when all the code is contained within a single file. However, as soon as I move the component to anoth ...

Designing a web application with Angular2

As a newcomer to Angular2, I have recently started working on creating a simple hello world application. I have come across the concept of Modules and Components in Angular2. My main source of confusion lies in how to properly design an Angular2 applicat ...