Troubleshooting a setTimeout filter problem in Vue

Implementing a notification system in Vue has been my latest project. I've created a Notifications component to store error messages that I want to display.

    data(){
        return {
            alerts: {
                error: []
            }
        }
    }

Whenever an event occurs in the root component, I add a message to the error array and then loop through them in the Notification template.

            <transition-group name="slide-fade">
                <Error v-for="(alert, index) in alerts.error" :key="index" :alert="alert" @removeError="removeError($event)"></Error>
            </transition-group>

In the Error component, each message is displayed along with a closing button.

**The challenge now is setting these messages to automatically close after 3 seconds. **

Here's how the Error component looks:

<template>

    <div class="alert alert-danger alert-dismissible" role="alert">
        {{alert.msg}}
        <button ref="closeButton" type="button" class="close" @click.prevent="remove()">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>

</template>

<script>
    export default {
        props: ["alert"],
        methods: {
            remove(){
                this.$emit("removeError", this.$props.alert);
            }
        },
        mounted(){
            setTimeout(() => {
                this.remove();
            }, 3000);
        }
    }
</script>

I trigger the removal either by clicking on the button or after 3 seconds with a setTimeout function. The event is caught back in the Notification component, where a method is called to filter out the message from the initial array:

        removeError(toRemove){
            this.alerts.error = this.alerts.error.filter(item => {
                return item !== toRemove;
            });
        }

The problem arises when having multiple errors pushed in the array and waiting for the timeout. Only some of those messages get filtered (like 2 or 3 out of 5), while others remain in the array.

Check out images of the result here:

Freshly pushed errors

Errors remaining after the timeout

An Update on the Issue:

The issue was caused by using keys in the Error component - Vue would get confused as the key of the array recalculates when an element is removed.

This led to another problem because Vue only accepts primitive keys, meaning they have to be either strings or numbers. But all I have as a key is the message itself, which might not always be unique, especially if two messages are the same. Any suggestions on how to overcome this challenge?

Answer №1

It seems like the issue may lie with the key attribute in your code snippet:

<Error v-for="(alert, index) in alerts.error" :key="index" :alert="alert" @removeError="removeError($event)"></Error>

Perhaps you could consider modifying the key as follows:

<Error v-for="(alert, index) in alerts.error" :key="alert" :alert="alert" @removeError="removeError($event)"></Error>

My assumption is that Vue might be getting confused due to the way keys are recalculated when an element is removed. I created a quick fiddle to replicate the issue, and it was resolved by using a key other than the index.

Vue.component('notification', {
  template: '#notification',
  props: ["error"],
  created() {
    console.log(`Removing ${this.error} in 3 seconds`);
    setTimeout(() => {
      console.log(`Removing ${this.error} now`);
      this.$emit("remove", this.error);
    }, 3000);
  }
});

new Vue({
  el: '#app',
  data: {
    errors: []
  },
  methods: {
    add() {
      this.errors.push("Test: " + this.errors.length);
    },
    remove(error) {
      console.log(error);
      this.errors.splice(this.errors.indexOf(error), 1);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<script type="text/x-template" id="notification">
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
  <div class="toast-header">
    <strong class="mr-auto">{{error}}</strong>
    <small>11 mins ago</small>
    <button type="button" class="ml-2 mb-1 close" @click="$emit('remove', error)">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="toast-body">
    Hello, world! This is a toast message.
  </div>
</div>
</script>

<div id="app">
<notification v-for="(error, index) in errors" :error="error" @remove="remove" :key="error"></notification>
<button class="btn btn-primary" @click="add">Add</button>
</div>

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

excess white space appears in the mobile version

I recently completed a website using both materializecss and bootstrap platforms. While I know this may not be the best practice, it worked for my needs. However, I am facing an issue with the mobile view. When I reduce the viewport size, a margin appear ...

How to incorporate markdown files as strings in Next.js

Is there a way to bring in markdown files as strings in Next.js for use on both the client and server sides? ...

Discovering time overlaps with Javascript and moment.js

In my calendar project, I am storing events for a day in an array. The start and end times are stored as String values in the following format: Example of events in a day const events = [{ "_id": "5bdf91a78197f0ced6c03496", "user": "5bd62237d6 ...

Unable to display Bootstrap 5 modal

I am currently in the process of constructing a basic webpage that includes a navigation bar and a table. The table rows are being dynamically generated through a simple JavaScript script that fetches data asynchronously from a database. I opted to utilize ...

Utilizing JQuery to extract the image title and render it as HTML code

I am currently facing an issue with displaying an image in my project. I want to hide the image using CSS (display: none) and instead, retrieve the value of its title attribute and display it within the parent div by utilizing JQuery. Despite knowing tha ...

Issues arise when attempting to run JQuery functions with the $ symbol in the head tag of HTML

Because of the limitations imposed by Squarespace, I am only able to include code via the Head tag. When the script reaches the $ part of JQuery, it seems to not execute at all. After testing with numerous console.log() statements, I observed that the webp ...

What are the steps to utilize the .find() method to search for documents in a database that belong to the current user

My back-end code for the 'get' request to my '/logs' collection returns data in an array labeled "times": router.get('/', (req, res) => { time .find({'userName': req.params.userName}) .exec() .then(times => ...

leveraging array elements in the data and label properties of a chart.js chart

I would like to assign the values of an array to the data and label fields within a chart.js dataset. Below is the code executed upon successfully fetching JSON data using an AJAX call. The fetched JSON data is then stored in an array. Data = jQuery.pars ...

What is the syntax for declaring a boolean or object type?

Is it possible to create a variable in TypeScript that can hold either true/false or an object of booleans? I'm still learning TS and would like some input on this syntax. variableA: { a: boolean, b: boolean } | boolean I found a workaround for now, ...

Having trouble accessing the vue.js front end after running npm build in combination with the frontend-maven-plugin and spring-boot backend

Inspiration: https://github.com/jonashackt/spring-boot-vuejs I am currently in the process of developing a vue.js frontend paired with a spring-boot backend using the frontend-maven-plugin. The structure of my project is as follows: webapp -> webapp ...

Tips for transmitting a batch of resources with Restangular?

Suppose I need to make a DELETE request to delete multiple products from the resource /products. The complete request should be sent to this URI: /products/ids=1&ids=2&ids=3 What is the method to send a request like this using Restangular? The c ...

Why does the Hamburger Menu shift my website's logo when it opens?

I'm in the process of implementing a hamburger menu on my website. My attempts have involved adjusting the positioning of both the #logo and .topnav elements. Code Snippet source function myFunction() { var x = document.getElementById("myTopn ...

Angular : How can a single item be transferred from an array list to another service using Angular services?

How to Transfer a Single List Item to the Cart? I'm working on an Angular web application and I need help with transferring a single item from one service to another service and also displaying it in a different component. While I have successfully i ...

Trouble encountered with updating the Input value upon pressing the enter key

In my ReactJS-based application, I am working on a component that includes a Material Input element. Users can enter words and when they press the enter key, those words are displayed as chips within the same input field. The issue I'm encountering i ...

What is the best method for storing a model in a database?

Hello, I am currently attempting to save a model to the database. I am simply inputting the value of a title in order to save it, as my id is set to auto increment. However, I have encountered an issue where my attempts have been unsuccessful. Can someone ...

Incorporating Javascript into a <script> tag within PHP - a step-by-step guide

I am trying to integrate the following code into a PHP file: if (contains($current_url, $bad_urls_2)) { echo '<script> $('body :not(script,sup)').contents().filter(function() { return this.nodeType === 3; ...

Click to add a card

Attempting to incorporate a new row with the click of a button dynamically has proven to be challenging for me. As someone who is relatively new to JavaScript, I am struggling to figure it out. In the demonstration provided below, you will notice that noth ...

Switch out the icons within a return statement in JavaScript

Help! I have 5 empty star icons (<StarBorderIcon/>) displayed for a product on the material-ui website. I need to replace them with filled star icons (<StarIcon/>) based on the rating entered into a function. I attempted to use replace(), but i ...

Adding options to a dropdown list dynamically within a ASP.NET Datagrid using Jquery

While the function in my 'aspx' page is functioning properly, I am facing an issue with the 'dropdown' inside the GridControl. It appears to be getting duplicated from the original row and not updating with the values from the appended ...

What is the best way to send props to a styled component without needing to convert them to transient props beforehand

Recently, I designed a custom Text component that accepts several props. These props are then forwarded to the styled component where specific styles are applied. However, I am facing an issue where I do not want these props to be passed down to the DOM, b ...