0

After setting a watcher on an input data , I am trying to display both old value and new value, but they are both undefined... what could be wrong ?

see codepen.io

HTML

<div id="app">
  <v-app id="inspire">
    <v-container mt-1 grid-list-xl">
      <v-layout row wrap justify-space-around>
        <v-flex d-flex sm6 md6>
          <v-layout row wrap>
            <v-flex d-flex>
              <v-card class="flexcard" dark tile flat>
                <v-card-title class="card__title justify-center">PROFILE</v-card-title>
                <form @submit.prevent="onUpdateProfile()">
                <v-card-text class="card__text grow">
                  <v-text-field  @keyup.native="setDirty" placeholder="Enter your new email address" :readonly="isReadOnly" label="Email" v-model="user.email" prepend-icon="email">
                  </v-text-field>
                </v-card-text>
                <v-card-actions>
                  <v-tooltip  v-if="isReadOnly" right>
                      <v-btn  @click="onEditProfile" icon class="primary" large slot="activator">
                       <v-icon color="white">edit</v-icon>
                        </v-btn>
                        <span>EDIT</span>
                  </v-tooltip>                                                                                          
                <v-btn v-if="isProfileEditing" round @click="cancel()">CANCEL</v-btn>
                <v-btn v-if="isProfileDirty" round color="primary" type="submit">UPDATE</v-btn>
                </v-card-action>
                </form>
              </v-card>
            </v-flex>
          </v-layout>
        </v-flex>
     </v-layout>
      </v-container>
  </v-app>
</div>

JS

new Vue({
  el: '#app',
  mounted () {
    this.user.email = '[email protected]'
  },
  data: () => ({
     user: {
      email: ''
    },
    cache: {
      user: {
        email: ''
      }
    },
    editIcon: {
      email: 'edit'
    },
    isProfileEditing: false,
    isProfileDirty: false,
    isReadOnly: true
  }),
  watch: {
    user: function (newUser, oldUser) {
      console.log('Old User Email: ', oldUser.email)
      console.log('New User Email: ', newUser.email)
    }
  },
  computed: {
  },
  methods: {
    onUpdateProfile () {
      console.log('UPDATE PROFILE: ', this.user.emaill)
    },
    onEditProfile () {
      this.isProfileEditing = true
      this.isReadOnly = false
      this.cache.user.email = this.user.email
      this.user.email = ''
    },
    cancel () {
      this.isProfileEditing = false
      this.isProfileDirty = false
      if (!this.isReadOnly) {
       this.isReadOnly = true
       this.user.email = this.cache.user.email
      }
    },
    setDirty () {
      this.isProfileDirty = true
    }
  }
})
1
  • console.log('UPDATE PROFILE: ', this.user.emaill) you trying to access property emaill here. But should email Commented Jul 11, 2018 at 7:39

2 Answers 2

2

To listen to changes for a property in an object you should add deep watcher. To do so add deep: true property to your watcher.

watch: {
  user: {
    handler: function (newUser, oldUser) {
      console.log('Old User Email: ', oldUser.email)
      console.log('New User Email: ', newUser.email)
    },
    deep: true
  }
}

Here is the updated pen

But if you are trying to make use of the oldUser , then the watcher cannot help you bacause:

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.

That's the reason you see the same value for both newUser and oldUser when user.email is updated.

Reference - vm.watch API

Sign up to request clarification or add additional context in comments.

2 Comments

Kishna . Thanks for this feedback ... I forgot it... god point regarding old value ... !!
@erwin Yup they are equal because in javascript objects are passed by reference. Both newUser and oldUser refer the same object.
0

If you want to watch for changes nested data you have to set deep option of watcher. However you can't access an old data in handler as Vue doesn’t keep a copy of the pre-mutate value of objects. In your case, the code of your watch object should look like this below:

watch: {
  user: {
    handler: function (newUser) {
      console.log('New User Email: ', newUser.email)
    },
    deep: true
  }
}

Reference: Vue's official API

1 Comment

Thanks for feedback ... however Vamsi Krishna answer is actually more detailed ... useful info about old and new values !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.