3

I have a watcher on a deep nested object. I am using Vue.set() to add a reactive property to the object. This is triggering the watcher but the both the newVal and oldVal console logs are showing the data with the new property added to it already rather than the oldVal showing what it was prior to adding the new property to it.

  <button @click="addData">Add</button>


  data() {
    return {
      myData: {
        time: {

        }
      }
    }
  },
  watch: {
    myData: {
      handler(newVal, oldVal) {
        console.log("NEW", newVal);
        console.log("OLD", oldVal);
      },
      deep: true
    }
  },
  methods: {
    addData() {
      this.$set(this.myData.time, 'other','testing')
    }
  }
MauirceA
  • 291
  • 1
  • 13
  • 1
    Does this answer your question? [Vuejs get old value when on change event](https://stackoverflow.com/questions/42197822/vuejs-get-old-value-when-on-change-event) – Terry Mar 01 '21 at 22:38
  • It’s mentioned in the API documentation that you can’t: VueJS does not keep a referencey to the before value of an object: https://vuejs.org/v2/api/#vm-watch – Terry Mar 01 '21 at 22:40
  • Does this answer your question? [Vue watch array push same old and new values](https://stackoverflow.com/questions/50682261/vue-watch-array-push-same-old-and-new-values) – João Hamerski Mar 01 '21 at 23:05

1 Answers1

3

As mentioned by @Terry, vue doesnt keep a referency to the oldValue, see what the docs says:

Note: when mutating (rather than replacing) an Object or an Array, the old value will be the same as new value because they reference the same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.


There is some ways you can solve that:

Using vanilla javascript

  • Add a computed property that returns your data property converting to a JSON string.
  • Use JSON.parse on your Watch function to convert the string back to a object.
data() {
  return {
    myData: {
      time: {

      }
    }
  }
},
computed: {
  computedMyData() {
    return JSON.stringify(this.myData);
  }
},
watch: {
  computedMyData: {
    handler(newValJSON, oldValJSON) {
      let newVal = JSON.parse(newValJSON),
          oldVal = JSON.parse(oldValJSON);
      
        console.log("NEW", newVal);
        console.log("OLD", oldVal);
      },
      deep: true
    }
  },
methods: {
  addData() {
    this.$set(this.myData.time, 'other','testing')
  }
}

Fiddle: https://jsfiddle.net/mLbuf6t0/

Using LODASH

  • Add a computed property that returns a deep clone from your data property with cloneDeep function.
data() {
  return {
    myData: {
      time: {

      }
    }
  }
},
computed: {
  computedMyData() {
    return _.cloneDeep(this.myData)
  }
},
watch: {
  computedMyData: {
    handler(newVal, oldVal) {            
      console.log("NEW", newVal);
      console.log("OLD", oldVal);
    },
    deep: true
  }
},
methods: {
  addData() {
    this.$set(this.myData.time, 'other','testing')
  }
}

Fiddle: https://jsfiddle.net/mLbuf6t0/2/

tony19
  • 125,647
  • 18
  • 229
  • 307
João Hamerski
  • 461
  • 1
  • 5
  • 22