Skip to content
Advertisement

Vue.js2 – Object.assign({}, this.var) preventing watch method

returning this.user (a global computed property) works as expected. Of course, I’m making a copy because I do not want to overwrite the actual user data. So, I’m using Object.assign. However, once I include return Object.assign({}, this.user) (opposed to this.user), the watch method no longer functions.

Here is my template (I am using bootstrap-vue):

<template>
  <form role="form">
    <b-form-group
      label="First Name"
      label-for="basicName"
      :label-cols="3"
      :horizontal="true">
        <b-form-input id="user-name-first" type="text" v-model="userFormData.fname"></b-form-input>
    </b-form-group>
          <b-form-group
      label="Last Name"
      label-for="basicName"
      :label-cols="3"
      :horizontal="true">
        <b-form-input id="user-name-lirst" type="text" v-model="userFormData.lname"></b-form-input>
    </b-form-group>
          <b-form-group
      label="Email"
      label-for="user-email"
      :label-cols="3"
      :horizontal="true">
        <b-form-input id="user-email" type="text" v-model="userFormData.email"></b-form-input>
    </b-form-group>
      <b-form-group
          :label-cols="3"
          :horizontal="true">
                    <b-button type="submit" variant="primary">Save changes</b-button>
            <b-button type="button" variant="secondary" @click="userFormCancel">Cancel</b-button>
        </b-form-group>
      </form>
</template>

So, this works and sets editsPending to true whenever changes are applied to userProfile (via v-model on an input)

<script>
export default {
  name: 'userProfile',
  data () {
    return {
      editsPending: false
    }
  },
  computed: {
    userFormData: function () {
      return this.user
    }
  },
  watch: {
    userFormData: {
      deep: true,
      handler (val) {
        this.editsPending = true
      }
    }
  },
  methods: {
    userFormCancel () {
      this.editsPending = false
    }
  }
}
</script>

…but this does not; userFormData becomes a clone of user but editsPending is not affected by updates to userFormData.

<script>
export default {
  name: 'userProfile',
  data () {
    return {
      editsPending: false
    }
  },
  computed: {
    userFormData: function () {
      return Object.assign({}, this.user)
    }
  },
  watch: {
    userFormData: {
      deep: true,
      handler (val) {
        this.editsPending = true
      }
    }
  },
  methods: {
    userFormCancel () {
      this.editsPending = false
    }
  }
}
</script>

Can anyone explain why this may be happening and suggest a viable solution?

Advertisement

Answer

A computed property will only re-evaluate when some of its dependencies have changed. (source)

That’s why it works with return this.user and not with Object.assign because it’s not a reactive dependency.

If you want reactive data you should initialize userFormData as an empty object data and assign your user when your Vue instance is created:

  data () {
    return {
      editsPending: false,
      userFormData: {}
    }
  },
  created() {
    this.userFormData = Object.assign({}, this.user)
  },
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement