What is the best way to initiate a change when adding a new property to an object in VueJs?

Here is the initial structure of my vuex state in a VueJS project:

state: {
    level1prop: null
}

After dynamically changing and mutating it, the structure becomes:

state: {
    level1prop: {
        level2prop: {
            level3prop: {
                "customKey1": { /* some object 1 */ },
                "customKey2": { /* some object 2 */ },
                ...
            }
        }
    }
}

I then continue to add

"customKeyN": { /* some object N */ }
under level3prop. It's important for me that every change triggers a watcher monitoring changes to level1prop in the state.

Initially, I used the following mutation update logic:

If (!state.hasOwnProperty("level1prop"))
    state["level1prop"] = {};
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state["level1prop"] = {};

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"]["level2prop"] = {};
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"]["level2prop"] = {};

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"]["level3prop"] = {};
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"]["level3prop"] = {};

let payloadObj = {  "customKey1": { /* some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

Although this setup creates the desired structure, the watcher is not triggered. Despite attempting various refactors based on advice from here, none have successfully triggered the watcher. Here is an example of one attempted option:

If (!state.hasOwnProperty("level1prop"))
    state = Object.assign(state, { "level1prop" : {} });
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state = Object.assign(state, { "level1prop" : {} });

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });

let payloadObj = {  "customKey 1": { /* some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);

While this approach also gives the desired structure, the watcher remains untriggered. Other attempts that failed to trigger the watcher include:

...
state["level1prop"]["level2prop"]["level3prop"] = Object.assign({}, state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

and

...
Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

Is there any effective way to trigger the watcher for changes in such a complex, deeply nested object state?

Answer №1

It is recommended in the documentation to use Vue.set for adding sub-levels to your state, as explained in the Object Change Detection Caveats section.

Ensure that your watcher includes the deep option to properly detect changes in your sub-levels.

const store = new Vuex.Store({
  state: {
    level1prop: null,
  },
});

const state = store.state;

if (!state["level1prop"])
  Vue.set(state, "level1prop", {})

if (!state["level1prop"]["level2prop"])
  Vue.set(state["level1prop"], "level2prop", {})

if (!state["level1prop"]["level2prop"]["level3prop"])
  Vue.set(state["level1prop"]["level2prop"], "level3prop", {})

let payloadObj = {
  "customKey1": {
    hello: "world",
  },
};
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

setTimeout(() => {
  // Change an already existing key.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
}, 1000);

setTimeout(() => {
  // To add or remove keys, make sure to use Vue.set or Vue.delete again.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
  Vue.set(state["level1prop"]["level2prop"], "level3propSibling", {
    hi: "again",
  });
}, 2000);


new Vue({
  store: store,
  watch: {
    "$store.state": {
      // Make sure you specify the `deep` option
      deep: true,
      handler() {
        console.log(store.state);
      },
    },
  },
});
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/vuex@3"></script>

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

Implementing SweetAlert2 in Vue.js to create a modal prompt for confirmation prior to deleting an item

I'm encountering an issue with sweetalert2 while using Laravel Vue for my app development. My goal is to have a confirmation modal pop-up when deleting a row from the database. However, whenever I click "Yes", the item is successfully removed. But if ...

Unable to pass an Array to the Controller

let formData = new FormData(); payloadData = JSON.stringify(payload.unitDoctors); for (var prop in payloadData) { formData.append(prop, payloadData[prop]); } axios({ method: "put", url: apiUrl + payload.id, data: formData }) .then(resp ...

"Error: Unable to access the property '$emit' of an undefined value" - VueJS

I'm currently working on implementing a basic authentication system in vuejs. I have a set of objects containing valid usernames and passwords. I am looping through this list to validate the entered username and password. If there is a match, I trigge ...

Toggle the visibility of table rows using checkboxes

I'm working with checkboxes to toggle the visibility of specific rows in a table based on their content matching the selected checkbox values. Checkboxes: <input type='checkbox' name='foo1' value='foo1' v-model="sele ...

When the state changes, initiate the animation

Currently, I am working with Vue.js and need to animate a navigation menu. My goal is to display two li elements when a user hovers over one of the navigation buttons. At the moment, I have set the data type showActivities to false by default and changed ...

Verify if the item already exists in the Vue.js array

Here is the data I have: data: function() { return { conversations: [ ] } } I am retrieving my data from the response object using response.data.conversation Is there a method to verify if this.conve ...

What is the process of inserting information into a nuxt-link in nuxt.js?

I am currently facing an issue with passing data into nuxt-link. Whenever I click on the link, nuxt-link returns a 404 error and fails to load the file. However, the other two links that use :href and hardcoding seem to be working fine. <template> ...

Can a variable be declared within the path references of the Firebase database?

In an effort to update my app's database references, I am working on implementing specific Firebase rules that involve adding buildings and depts nodes inside the user node. This decision was prompted by a discussion on best practices for writing Fire ...

Vue.js is unable to render the template using Object

During this demonstration at https://jsfiddle.net/ccforward/fa35a2cc/, I encountered an issue where the template could not render and the data in resultWrong remained empty with a value of {} At https://jsfiddle.net/ccforward/zoo6xzc ...

Unlock the potential of JavaScript by accessing the local variable values in different functions

I've been struggling for days to find a solution to this issue... https://i.stack.imgur.com/KDN7T.jpg https://i.stack.imgur.com/tOfCl.jpg The image above illustrates the challenge I'm facing - trying to apply data values from elsewhere to the ...

Retrieve Javascript files from the local static directory

Currently, I am developing a small project with Nuxt JS and I am facing a challenge in calling some Javascript files from my static directory. When it comes to CSS files, I have been able to do it successfully using the following code: css: [ './stat ...

Copy password input field content in Vue to clipboard

I'm currently working on a Vue app that includes a form input for creating passwords. I've managed to implement a button that shows/hides the password, but I'm struggling with adding a copy to clipboard function. It doesn't seem to be w ...

When using v-for to render components and <selection>, is there a way to customize it for just one specific instance of the component?

How can I modify the selection in each instance separately when rendering elements of an array obtained from the backend using v-for? Currently, changing one selection affects all instances due to the v-model. Is there a way to target only one selection ...

Information displays instantly in the initial milliseconds

When developing dynamic web pages with Nuxt, I encountered an issue in the pages directory where a file named _url.vue is located. The contents of this file are as follows: <template lang="pug"> div component( v-for= ...

Guide on inserting a new column into an array of objects in Vue

Below is the fetch method I have defined to retrieve recordings from the database. However, I need assistance in adding a new column to each record specifically for frontend purposes. Can someone help me with this problem? <script> export default { ...

Listen to music on an Android device without disturbing anyone using an iPhone

I have an application built in Vue3 that plays a sound when a QR code is scanned. This feature works perfectly on Android and the web, but not when using the browser on iOS. I am struggling to identify the issue. Can anyone provide some insight? <qrco ...

Vue.js v-cloak lifecycle method

Currently, I am working on a project where I have styled v-cloak with display: none, and it is decorating the body. As a result, everything remains hidden until the Vue instance is ready. I have created a component that inserts a chart (using highcharts). ...

What is the correct method for downloading an Excel file in a Vue.js application?

I am having difficulty downloading an Excel file in xlsx format using my Vue.js application. The Vue.js application sends a post request to the Node.js application which then downloads the Excel file from a remote SFTP server. The backend application is fu ...

Using a function as a prop in Vue js to retrieve data from an API

I am facing an issue with a component that I want to decouple from the data fetching implementation. My goal is to be able to pass a data fetching callback as a prop. The reason for this is so that I can easily mock the data fetching process in storybook. ...

The chosen option in the q-select is extending beyond the boundaries of the input field

Here's the code snippet I used for the q-select element: <q-select square outlined fill-input standout="bg-grey-3 text-white" v-model="unit_selection" :options="units&qu ...