Rahul Gupta
Rahul Gupta

Reputation: 69

Watching nested object in Vue using deep

I'm trying to watch the data object with multiple properties using deep invocation, I need to know in the watch call is triggered for which property change in the object. Is there any way to know the property in the handler.

data(){
   return {
        user:{
           first_name:'',
           last_name:'',
            }
    }
},
watch:{
    user:{
       deep:true,
       handler(value){
       //Here I want to know which property(first_name/last_name) change of the user object has triggered this.
        }
    }
}

Upvotes: 1

Views: 3152

Answers (2)

Grumaks
Grumaks

Reputation: 159

It seems vue doesn't have a way to determine what property changed.

Using your example fires watch callback when any property changed.

But vue has one more option:

// keypath
vm.$watch('a.b.c', function (newVal, oldVal) {
  // do something
})

https://v2.vuejs.org/v2/api/#vm-watch

In your case it may be something like this:

data(){
   return {
        user:{
           first_name:'',
           last_name:'',
            }
    }
},
watch:{
    "user.first_name": function(newVal, oldVal) {
      // todo
    },
    "user.last_name": function(newVal, oldVal) {
      // todo
    }
}

But I'm not sure that it's good way

upd from vue documentaion

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.

Manualy compare object is useless in this case because newVal = oldVal (one reference)

upd2: re-creating an object may be warkaround

// for example
user = Object.assign({}, user, { first_name: "newValOfFirstName" })

// instead of
user.first_name = "newValOfFirstName";

Upvotes: 1

Gabriel Willemann
Gabriel Willemann

Reputation: 1921

You can do something like this:

<template>
  <div>
    <div>
      <input type="text" v-model="obj.prop1" />
      <input type="text" v-model="obj.prop2" />
      <input type="text" v-model="obj.prop3" />
    </div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data: () => ({
    obj: {
      prop1: '',
      prop2: '',
      prop3: '',
    },
  }),
  mounted() {
    for (const key in this.obj) {
      this.$watch(
        () => this.obj[key],
        (newValue, oldValue) => {
          console.log(key, oldValue, newValue);
        }
      );
    }
  },
};
</script>

With this.$watch method you can create dynamic watchers.

For more details, you can see the documentation: https://v2.vuejs.org/v2/api/#watch

Upvotes: 1

Related Questions