Reputation: 4292
In the code below I'm 2 way binding the output of a textarea into a p element, once from the component's internal state and once from Vuex. The Vuex state does show the initial value, but the value doesn't update as I add or delete text (as it does correctly with the 1st textarea bound to the internal data). What is the difference that is causing this issue?
Component code:
<template>
<div>
<div>
<textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="internal_state"></textarea>
<p> {{ internal_state }}</p>
<hr>
<textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="this.$store.state.vuex_state"></textarea>
<p> {{ this.$store.state.vuex_state }}</p>
<hr>
</div>
</div>
</template>
<script>
export default {
name: 'WriteArea',
data () {
return {
internal_state: ''
}
},
methods: {
}
}
</script>
Vuex code:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
strict: true,
state: {
counter: 0,
vuex_state: 'starting string'
},
getters: {
vuex_getter1: (state) => {
return state.vuex_string
}
}
})
Upvotes: 7
Views: 10606
Reputation: 3994
from vuex-map-fields repo:
Enable two-way data binding for form fields saved in a Vuex store.
Vuex Store
import Vue from 'vue'
import Vuex from 'vuex'
import { getField, updateField } from 'vuex-map-fields';
Vue.use(Vuex)
export const store = new Vuex.Store({
strict: true,
state: {
counter: 0,
vuex_state: 'starting string'
},
getters: {
getField, // Add the `getField` getter to the `getters` of your Vuex store.
vuex_getter1: (state) => {
return state.vuex_string
}
}
mutations: {
updateField, // Add the `getField` getter to the `getters` of your Vuex store.
}
})
Component code:
<template>
<div>
<div>
<textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="internal_state"></textarea>
<p> {{ internal_state }}</p>
<hr>
<textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="vuex_state"></textarea>
<p> {{ vuex_state }}</p>
<hr>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields';
export default {
name: 'WriteArea',
data () {
return {
internal_state: ''
}
},
computed: {
// The `mapFields` function takes an array of
// field names and generates corresponding
// computed properties with getter and setter
// functions for accessing the Vuex store.
...mapFields([
'vuex_state ',
]),
},
}
</script>
Upvotes: 0
Reputation: 562
You can try to use mine library for 2 way binding vuex problem solution
https://github.com/yarsky-tgz/vuex-dot
Example:
<template>
<input v-model="name"/>
<input v-model="email"/>
<button @click.stop="step++">next</button>
</template>
<script>
import { takeState } from 'vuex-dot';
export default {
computed: {
step: takeState('wizard.step')
.commit('setWizardStep')
.map(),
...takeState('user')
.expose(['name', 'email'])
.commit('editUser')
.map()
}
}
</script>
store/index.js
export default new Vuex.Store({
state: {
wizard: {
step: 1
},
user: {
name: 'John',
email: '[email protected]'
}
},
mutations: {
setWizardStep(state, step) {
state.wizard.step = step;
},
editUser(state, patch) {
state.user = Object.assign({}, state.user, patch);
}
}
});
Upvotes: 2
Reputation: 1810
Vuex state should be updated via a mutation. See the documentation for this exact problem. Solution is not to use v-model, but instead to bind to the :value
of the textarea
and then have a custom event to mutate the Vuex state on input:
https://vuex.vuejs.org/en/forms.html
<input :value="message" @input="updateMessage">
// ...
computed: {
...mapState({
message: state => state.obj.message
})
},
methods: {
updateMessage (e) {
this.$store.commit('updateMessage', e.target.value)
}
}
The other option is to create a setter and getter in the same computed property:
<input v-model="message">
// ...
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
Upvotes: 10