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

What is the correct method of implementing the "OnChange" event to a WooCommerce select element?

My task is to include the onchange="myFunction()" in the select menu below. However, because the select menu is part of woocommerce, I want to ensure that the onchange="myFunction()" remains intact even after updating my theme. How can I achieve this goal ...

Issues with Angular's http get functionality not functioning as expected

I'm experimenting with an API on apiary.io and attempting to retrieve data from it using Angular, but I'm encountering issues with the call. The setup seems straightforward, so I'm not quite sure what's causing the problem: HTML: < ...

Is it better to have JavaScript and HTML in separate files or combined into a single HTML file?

Do you notice any difference when coding in both HTML and JavaScript within a single .html file compared to separating HTML code in a .html file and JavaScript code in a .js file? Does the functionality remain the same in both scenarios? For example, in t ...

Issue with Vuetify table customization not persisting on the first row after refreshing the page

Enhance Your Table Interface: <v-card :dark="true"> <v-card-title> <v-btn color="indigo" dark @click="initialize"><v-icon dark>refresh</v-icon></v-btn> <v-spacer></v-spacer> &l ...

Unable to transform undefined or null into an object within Next.js

Hi there! Currently, I am working on creating a login page using Next.js and next-auth. I have included the necessary providers in the providers array within [...nextauth].js. However, when I attempt to run the following code: import { getProviders, signIn ...

Is relying on jQuery to submit a form without the use of PHP secure?

My website has a user account creation form with a "submit" button that is actually an html type='button', not a true submit button. When this button is clicked, I rely on jQuery to call ('#form').submit(); in order to submit the form. ...

Use jQuery to display the user input value in real-time

I am in the process of developing a dynamic calculation program to sharpen my jQuery skills, but unfortunately, I'm facing some challenges. I have managed to store values in variables as shown in the code snippet below. <form> Table of: ...

Implement the color codes specified in the AngularJS file into the SASS file

Once the user logs in, I retrieve a color code that is stored in localstorage and use it throughout the application. However, the challenge lies in replacing this color code in the SASS file. $Primary-color:#491e6a; $Secondary-color:#e5673a; $button-color ...

Clicking to close tabs

I am currently working on implementing a tab functionality on my website and I want these tabs to be responsive. Here is the code snippet I have been using: function openCity(evt, cityName) { var i, tabcontent, tablinks; tabcontent = document.ge ...

When attempting to connect to http://localhost:8545/ using Web3.js, the network encountered an error with the message

I am currently working on setting up web3.js for a website in order to enable Ethereum authentication. However, I encountered the following error: web3-light.js:4327 OPTIONS http://localhost:8545/ net::ERR_CONNECTION_REFUSED HttpProvider.send @ web3- ...

The state of my React components keeps disappearing

Within my code, I have implemented a click event on the InterestBox to trigger updates in its appearance and alter the state of its parent container. However, despite inspecting the element using React Developer Tools and attempting API requests, the stat ...

Troubleshooting issues with NodeJS and Express authentication middleware functionality

I am currently working on implementing the isUserAuthenticated function to run on every server request. This function is required in the app.js file and utilized using app.use(authenticate.isUserAuthenticated). In my project, there is an /authenticate rou ...

Issue with Type-Error when accessing theme using StyledComponents and TypeScript in Material-UI(React)

I attempted to access the theme within one of my styled components like this: const ToolbarPlaceholder = styled('div')((theme: any) => ({ minHeight: theme.mixins.toolbar.minHeight, })); This information was found in the documentation: htt ...

The lower text box on the page being covered by the virtual keyboard on IOS

Our website features a fixed header and footer with scrollable content. We have 20 text boxes on the page, but the ones at the bottom, like Zip and Telephone, are obscured by the iOS virtual keyboard that appears when a text box is clicked. If we could d ...

What is the best way to implement an undo-list using arrays?

My current project involves creating a paint program in JavaScript, and I am aiming to implement an undo function rather than just an eraser. How can I store events in an array and then enable the deletion of each event individually? I have a dropdown men ...

Mastering the art of square bracket destructuring in React through deep comprehension of the concept

import React, { useEffect, useState } from 'react' import { Text } from 'react-native' export default function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount((co ...

Utilizing Vue's string-based class binding feature?

Can Vue class binding work with strings? For example: <div :class={open: target == 'myString'}></div> var app = new Vue({ target: null }) It works when I don't use quotes <div :class={open: target == myString}></div ...

Is it possible to remove the browsing history of user inputs in JavaScript?

I'm currently working on a Simon Says game where the level of difficulty increases as players correctly repeat the pattern. However, I encountered an issue with clearing the input history that shows previous patterns entered by the user. How can I res ...

When calling UIComponent.getRouterFor, a TypeScript error is displayed indicating the unsafe return of a value typed as 'any'

I have recently integrated TypeScript into my SAPUI5 project and am encountering issues with the ESLint messages related to types. Consider this simple example: In this snippet of code, I am getting an error message saying "Unsafe return of an any typed ...

Update the Vue component upon fetching new data

How can I continuously refresh the list of items when a button in a sibling component is clicked? The watch method only triggers once, but I need it to constantly refresh. This is the parent element: <template> <div class="container"& ...