0
votes

**** UPDATE ****

Solution : Not bothering to tie the Vuex state to the form. I realized it's not worth the trouble, and I can still serialize the form data and send it along anyway using the standard conventions. Had a total rethinking of not needing to tie so many elements into JS objects.

**** ORIG ****

Alright, can someone please tell me what I'm missing here.

I want to update the state in a mutation function, and have the changes reflect in the input fields. Crazy right? I guess there's trouble with updating object properties, so in the example I have both referencing the object property and defining a specific getter for the property, neither of which are working. Then to represent updating the state outside of the input field, I just have a button below that does this.

Template:

<input :value="user.first_name" @input="UPDATE_USER" />
OR
<input :value="first_name" @input="UPDATE_USER" />
<button v-on:click="updateName">Update</button>

Component:

computed: {
   ...mapState({
        user: state => state.user,
        first_name: state => state.user.first_name // specific getter for the property
    })
},
methods: {
    ...mapActions([
        UPDATE_USER,
    ]),
    updateName () {
        this.$store.dispatch(UPDATE_USER_NAME, "anything");
    }
}

Action:

[UPDATE_USER_NAME] ({commit}, name) {
    commit("updateUserName", name);
},
// Omitted UPDATE_USER function, just takes e.target.name / value and it works anyway

Mutations:

updateUserName (state, name) {
    Vue.set(state.user, "first_name", name);
}

Expected: Click the button, it updates the state, and the input field value shows "anything".

Actual: Click the button, it updates the state, but the input field value is not updated. This goes for both input fields, one which references the object property directly, and the other which has its own getter.

Editing the input fields works fine, so it's like it works top-down but not bottom-up. What the heck am I missing?

3
Why not mapActions UPDATE_USER_NAME and call it like this.UPDATE_USER_NAME(name) ?vapurrmaid
Is there a reason v-model can't be used within the component, and values in state are only updated on an action method? The <input> could still be initialized with a value from the store.vapurrmaid
Yeah I'm playing around with v-model and using get() set() to handle updates, unfortunately with the same result. In fact the example I have updates via action, see it's passed into @inputcoleman-benjamin

3 Answers

3
votes

Note: I tested this locally but I don't know exactly how the store state looks from the question.

The <input> can be two-way bound with v-model, instead of computed or watched. It can be initialized with a value from the store (I used the mounted lifecycle hook below). The store state is updated only on button click.

<input v-model="firstName"/>
<button @click="updateName">Update</button>
import { mapActions, mapGetters } from 'vuex'

export default {
  data () {
    return {
      firstName: ''
    }
  },
  
  computed: mapGetters(['getFirstName']),

  methods: {
    ...mapActions(['UPDATE_FIRST_NAME']), // get the action from the store

    updateName () {
      // validations can go here etc
      this.UPDATE_FIRST_NAME(this.firstName) // update vuex store state
    }
  },

  mounted () {
    this.firstName = this.getFirstName // initialize this.firstName -> <input> 
  }
}

With this solution, you'd have to make sure to create the getter in your store, as in the following example:

const state = {
  user: {
    firstName: ''
  }
}

const getters = {
  getFirstName: state => state.user.firstName
}

1
votes

You need to watch the state variables. When it change the value, the the watch function will fire.

 export default {
    data() {
        return {
            dummy_name: '',
            first_name: '',
        }
    },
    created(){
    },
    computed: {
        dummy_name() {
            return this.$store.state.user.first_name
        },
    watch: {
       dummy_name() {
            this.first_name = this.dummy_name
       }
    }

Hope this will help, and get some idea how watch and computed work.

0
votes

This is an old question, but I ran into the same problem yesterday and the solution was to use the .prop modifier on the input value attribute like so:

<input :value.prop="first_name" @change="updateName" />

A quote from quite random place in the docs says:

For some properties such as value to work as you would expect, you will need to bind them using the .prop modifier.

Hope this helps someone!