Observing unexpected behavior with Vuex state updates when using v-model

One approach I've taken is creating a global error state using Vuex, which consists of an array containing objects representing all current errors.

const store = new Vuex.Store({
  state: {
    errors: []
  },

  getters: {
    getErrors: state => state.errors
  },

  mutations: {
    setError: (state, message) => {
      state.errors.push({ error: true, message });
    },
    removeError: (state, i) => {
      state.errors.splice(i, 1);
    }
  }
});

I have a component that dynamically displays all errors based on the Vuex state. My aim is to remove objects from the array where the error property is set to false. This property is controlled by the setError mutation and v-model within the component.

To achieve this, I'm attempting to watch for changes and remove the desired items from the array. However, it doesn't seem to be removing them immediately when the property changes to false. How can I fix this?

You can view a live demo here.

<template>
  <div id="snackbar">
    <v-snackbar
      v-for="(error, index) in getErrors"
      :key="index"
      v-model="error.error"
      color="red"
      :right="true"
      :timeout="2000"
      :top="true"
    >
      {{ error.message }}
      <v-btn dark text @click="removeError(index)">Close</v-btn>
    </v-snackbar>
  </div>
</template>

<script>
import { mapGetters, mapMutations } from "vuex";

export default {
  name: "ErrorSnackbar",

  computed: mapGetters(["getErrors"]),

  methods: {
    ...mapMutations(["removeError"]),
    removeError(i) {
      this.$store.commit("removeError", i);
    }
  },

  watch: {
    getErrors: {
      handler(newErrors) {
        if (newErrors.length > 0) {
          newErrors.forEach((error, i) => {
            if (error.error === false) {
              newErrors.splice(i, 1);
            }
          });
        }
      },
    }
  }
};
</script>

Answer №1

If you want your watcher to respond to changes in the array, including changes to items within the array, you need to use a deep watcher that observes all levels of the data structure.

When looping over an array and removing items simultaneously, make sure to iterate in reverse order to avoid missing elements during removal.

watch: {
  getErrors: {
    deep: true,
    handler(newErrors) {
      for (let i = newErrors.length - 1; i >= 0; i--) {
        if (!newErrors[i].error) {
          newErrors.splice(i, 1)
        }
      }
    }
  }
}

Keep in mind that mutating the observed data can trigger additional calls to the watcher function.


EDIT

Appreciate the codesandbox.

The issue with <v-snackbar> not updating the model is related to components being reused and their timeout getting canceled without emitting an input event when multiple errors are added or removed simultaneously.

To resolve this, ensure each <v-snackbar> component is keyed correctly to a unique ID associated with each error object, instead of relying on the index position in the array which changes dynamically.

Consider making these code changes:

// Global variable declaration
let nextKey = 1

mutations: {
  setError: (state, message) => {
    state.errors.push({
      key: nextKey++,
      error: true,
      message,
    })
  }
}
<v-snackbar
  v-for="error in getErrors"
  :key="error.key"
>

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

Node.js - Retrieving POST request parameters and directing users in an Express application

I encountered this specific issue while setting up a post endpoint for my nodejs CLI script that utilizes express to handle requests. app.use( express.static( path.format({dir: __dirname, base: 'client/dist'})) ); app.use( express ...

Guidelines for utilizing React to select parameters in an Axios request

As a newcomer to ReactJs, I am working with a Product table on MySQL. I have successfully developed a dynamic table in the front-end using ReactJS along with MySQL and NodeJs on the backend. The dynamic table consists of four columns: Product, Quantity, Pr ...

Pattern for regex to match the following example: test test123

Regular expression pattern for the test example "test test123". The first string should consist of only alphabets (A-Za-z), while the second string should be a combination of alphabets and numbers (A-Za-z0-9). Examples: 1. hello world123 (true) 2. 123 hel ...

A guide to checking an array of objects by their ID and assigning a new property using JavaScript

I am working with two arrays of objects called arr1 and arr2 If the ID in both arr1 and arr2 matches, I want to add the property names from arr1 to arr2 using JavaScript var arr1 = [ {id: 1, name : "Helena"}, {id: 2, name : "John"} ...

Having difficulty transferring a Vanilla JavaScript Class Object to a Vue.js application, encountering an error stating that the element is not defined

I am in the process of developing a game project. The core structure is being built using game objects that are derived from JavaScript classes with constructors. I initially created it using plain JavaScript and HTML, but encountered challenges when attem ...

What is the process for inserting a scroll bar within a div element?

   I have recently created a webpage using some divs, along with a bit of CSS and JavaScript. I am struggling to figure out how to add a scrollbar to one of my divs. The code is not overly complex, as it includes both CSS and JavaScript. <html> & ...

Avoiding 0 being mistakenly interpreted as undefined while utilizing React Conditional Rendering

I have a React component with the following code in its render function: return ( <div> {rating.score && ( <div>do something</div> )} </div> ); The prop rating.score is of type PropTypes.number. Eve ...

What is the process for dynamically including a document in a collection?

I am currently developing an accounting system that allows users to dynamically create accounts in the chart of accounts. Each time a new account is created, the app also generates a new collection for that specific account. Here is an example: const a ...

Guide to modifying component properties in Storybook

Currently, I am experimenting with storybook (here) to test my components in isolation. My goal is to simulate the entire flux cycle (typically handled using redux in the full app) and modify a property by utilizing a simple object within the story. Howeve ...

The duration of user engagement on a website with an embedded iframe

I am working on measuring the time users spend on web pages, excluding the time they navigate away from the browser. While exploring open source libraries like Timejs, I noticed that these tools do not accurately track user time when they are watching vid ...

Guide to accessing component methods within slots using the Vue 3 Composition API

I have child components within a slot in a parent component and I am trying to call methods on them. Here are the steps I followed: Use useSlots to retrieve the child components as objects Expose the method in the child component using defineExpose Call t ...

Is it possible to pass a parameter to a PHP controller using JavaScript without relying on jQuery or AJAX?

Is it possible to achieve the task at hand? That's the main question here. My goal is to extract data from a popup window and then, upon closing it, send this extracted content to a PHP controller for further processing. I'm facing conflicts wi ...

Enhancing Your React.js app with Script Insertion Using HTML/JSX

I'm attempting to apply a style to an HTML element only when the property of an array of objects meets a certain condition, but I encountered this error: /src/App.js: Unexpected token, expected "..." (35:25) Here's my code: codesandbox export de ...

Please disable zoom functionality on the website specifically for Android devices

Is there a way to disable the zoom feature on our website specifically for Android phones/devices without affecting iPhones? Perhaps targeting the Chrome browser on Android would be sufficient, but we should also verify the mobile screen size. ...

Tips for looping through multiple states within a single table

I need help with combining data from two different states, campaigns and stats, into a single table. The campaigns state includes sr no, campaign id, campaign name, and campaign status, while the stats state includes reach, sent, delivered, views, clicks ...

Using the Context API dispatch (consumer) within the _app.js class component in Next.js

How can I access the dispatch Context API methods in the _app.js file? The issue I am facing is that I am using React hooks along with Context API, and as _app.js is a Class component, I cannot directly use hooks within it. Below is my current code snipp ...

Wondering how to optimize FullCalendar for mobile and touch events?

I am looking to incorporate a drop event feature into the mobile version of fullcalendar. To achieve this, I am utilizing Jquery UI Touch Punch. After researching on various platforms such as Stack Overflow 1, Stack Overflow 2, Stack Overflow 3, Stack Ove ...

How a JavaScript Alert is disrupting the design of my ASP.NET Web Application

Despite finding a similar question, the provided answer did not resolve my issue. This is how my application typically appears: However, after triggering a JavaScript alert, the width of menu items becomes distorted and an additional part is added to the ...

I'm facing an issue with converting my object to an array as I keep getting the message: "ERROR TypeError: undefined

ERROR TypeError: undefined is not a function Why am I unable to convert my object to an array? This error keeps popping up as I attempt to map all the items that are currently objects but need to be converted into arrays for mapping. How can I accomplish ...

Determine the card type based on the card number

My array of card types is structured like this: var cards = new Array(); cards [0] = {name: "VISA", length: "13,16", prefixes: "4", checkdigit: true}; cards [1] = {name: "VISA_DELTA/ELECTRON", length: "16", prefixes: "417500,4917,4913", checkdigit: tr ...