What could be causing the lack of updates for a watched object in vue?

Although there are many similar questions on this topic, mine has a unique twist. After delving into reactivity in depth, I feel like I have a solid grasp of the concept. However, one thing continues to baffle me:

Summary:

Why does a watched property detect changes when initialized using

currentValue = Object.assign({}, currentValue, initValue)
, but not with a straightforward assignment like currentValue = initValue;?

I have an object called scoreRules registered on the model of my Vue component.

In the mounted hook,

  1. I reset the model's scoreRules by doing this:

this.$data.scoreRules = initScoreRules;

(I'm using initScoreRules as a prop which is locally declared below for this question).

  1. I watch for changes in scoreRules and log "score has been changed" whenever the object changes.

This code snippet illustrates the scenario:

new Vue({
  el: '#app',
  data() {
    return {
      scoreRules: {
        type: 'number',
        minimum: null,
        maximum: null
      }
    }
  },
  mounted() {
  let initScoreRules = {type: 'number'};
    this.$data.scoreRules = initScoreRules;
    this.$watch('scoreRules', ()=>{console.log("score has been changed")}, {deep: true});
  }
});
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>

<body>
  <div id="app">
    <span>Minimum score</span>
    <input type="number" name="minimumScore" v-model.number="scoreRules.minimum" />
</body>

</html>

When typing in the input field, the watch doesn't capture this change and nothing gets logged to the console.

If I then reinitialize scoreRules using

this.$data.scoreRules = Object.assign({}, this.$data.scoreRules,  initScoreRules);

new Vue({
  el: '#app2',
  data() {
    return {
      scoreRules: {
        minimum: null
      }
    }
  },
  mounted() {
    let initScoreRules = {};
    this.$data.scoreRules = Object.assign({}, this.$data.scoreRules,  initScoreRules);
    this.$watch('scoreRules', () => {
      console.log("score has been changed")
    }, {
      deep: true
    });
  }
});
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>

<body>
  <div id="app2">
    <span>Minimum score</span>
    <input type="number" v-model.number="scoreRules.minimum" />
  </div>
</body>

</html>

The changes are now detected and recorded in the console. But why? My suspicion is that it relates to the inner workings of JavaScript itself, although the exact mechanism still eludes me.

Answer №1

The original object initially had the properties minimum and maximum. However, in the mounted lifecycle hook, you did the following:

let initScoreRules = {type: "number"};
this.$data.scoreRules = initScoreRules;

As a result, the scoreRules object no longer contains those properties.

In Vue, changes can only be observed for properties that are either:

  • defined in the data() method (which was initially done but then reverted in mounted)
  • set using Vue.set() / this.$set()
  • present on an object assigned to a reactive property

This last point is also why the second example functions as expected. In this case, you essentially do this (omitting the use of Object.assign for clarity):

this.$data.scoreRules = { minimum: null }; 

This new property will now be reactive.

To learn more about this topic, visit:

https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

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

Retrieve dashboard configurations in AngularJS by making an $http request prior to initiating the dashboard controller

I am currently immersing myself in Angular and tackling a complex dashboard framework all built with Angular. Prior to loading the controllers, I need to fetch various dashboard settings from the server using $HTTP. These settings play a crucial role in de ...

How to Align Text and Image Inside a JavaScript-Generated Div

I am attempting to use JavaScript to generate a div with an image on the left and text that can dynamically switch on the right side. What I envision is something like this: [IMAGE] "text" Currently, my attempt has resulted in the text showing ...

Experiencing a hiccup in React while attempting to play an mp3 file

My project includes the following code snippet, with an example mp3 file and npm package: https://www.npmjs.com/package/react-sound import React from 'react'; import Sound from 'react-sound'; class CustomSound extends React.Component ...

Retrieving a dynamic JSON object for the MusicBrainz application using AngularJS

I want to incorporate a search form into my application that sends the form result to the specified link. I am retrieving artist names from the musicbrainz JSON database using the following request: "NAME OF AN ARTIST"%20e*&fmt=json The "NAME OF AN AR ...

Adjust google maps to fill the entire vertical space available

I found this helpful resource for integrating Google Maps into my Ionic app. Everything is working smoothly, but I am trying to make the map fill the remaining height below the header. Currently, I can only set a fixed height in pixels like this: .angula ...

Enabling the value to be set as true for radio buttons generated using v-for

Utilizing a v-for loop over an array of objects in graphicState, the rows of a table are dynamically generated. My goal is to implement a column of radio buttons that, when checked, will set graphicState[index].selected to true. I came across this insight ...

Error encountered in NextJS: Trying to call res.unstable_revalidate which is not a function

I recently tried out a cutting-edge feature introduced in NextJS v.12.1 . The API itself is functioning correctly and can be accessed. However, I encountered a 500 error with the message res.unstable_revalidate is not a function. This issue persisted wheth ...

Displaying Dynamic Content in React Table Rows Based on Conditions

I'm populating a table with multiple rows using props. If a returned prop is an empty string "" , I want to exclude that row from rendering. <Table.Body> <Table.Row> <Table.Cell>Producer</Table.Cell> ...

"Discover the steps to seamlessly integrating Snappuzzle with jQuery on your

I am a beginner when it comes to javascript and jquery, and I recently came across the snappuzzle plugin which caught my interest. After visiting snappuzzle plugin, I decided to download and link jQuery, jQuery UI, and the snappuzle.js in my HTML file. I a ...

Chrome Extension: Sending Data from Panel Window to Popup - A Step-by-Step Guide

I've been developing a Chrome extension that displays a window (popup.html) containing a button for playing videos when the extension icon is clicked. Upon clicking the play button, another window created using window.create of type panel opens up. Th ...

The peculiar formatting issue with the jQuery datepicker that arises when adding more months

When adjusting the numberOfMonths parameter to a higher value such as 6, I noticed that the datepicker display appears unusual with the background extending further than expected. Take a look at my demonstration on jsfiddle: http://jsfiddle.net/zw3z2vjh/ ...

Information failed to load into the datatable

i've implemented this code snippet to utilize ajax for loading data into a datatable. However, I'm encountering an issue where the data is not being loaded into the database. $('#new_table').DataTable({ "processing": true, "ser ...

Create vertical boundaries with the chartjs-plugin-annotation in conjunction with vue-chartjs

Trying to set 2 vertical lines as thresholds for a list of results from various tests. The issue arises when attempting to place the lines at values that do not exist within the result set, causing them to disappear. However, with the code below, the lines ...

What is the best way to access an error's body in order to retrieve additional error message details when using the forge-api with nodejs?

I'm struggling to retrieve the body content when an error is returned from the API request. I've attempted creating a bucket with uppercase letters, but all I receive is an error object with statusCode = "400" and statusMessage = "BAD REQUEST". ...

Ensure that my program is halted until the xmlhttprequest has completed

It seems like I've overcomplicated this problem for myself. In my page, I have 2 XMLHTTPRequests - the first request retrieves data from an API and fills my elements with this data. However, one of the fields in my elements requires a second request t ...

Substitute empty spaces and organize the text layout

I'm struggling to figure out how to substitute the whiteSpace in an aggregate request using MongoDB and also how to remove a specific part of a string (most likely requiring regex). Here's an example of my document: { "_id": "57dfa5c9xxd76b ...

Error encountered when attempting to retrieve data from a JSON object

I'm in the process of extracting some information from a JSON object, but I've encountered a confusing issue. The JSON object structure is as follows: { "status": "success", "data": { "image": null, "video": null, "author": null, "publisher": "M ...

Load subtitles into your video in real-time

Let's discuss the scenario: The server is receiving a stream of SRT file. This stream is then converted into VTT format by the server, which is further buffered and sent to the client through an io.socket connection. Below is the server-side code: s ...

Show the current time of a track using VueJS

Is there a way to have the time continuously update itself without needing to click on anything? When I press play, I want the seconds to automatically start updating from 0:00 until the end of the audio track. Currently, the time only updates when clicked ...

Unexpected state being returned by Vuex

I am encountering an issue with a pop-up modal that is not behaving as expected. The condition for the pop-up to appear is if the user has no transactions, which is determined by checking the length of the depositHistory array. If the length is greater tha ...