Problem
Let's say you want to save the input of your form on the state of vuex.
Maybe someone new to vuex would try something like this:
<input id="name" name="name" type="text" v-model="$store.state.user.name">
If you try this you will see that:
- It doesn't work
- Even if it worked, it is totally against the purpose of vuex, that is never have a change of state without it being made by a mutation.
Always send a mutation to change something.
Now, with that in mind, if you look into the documentation of vuex you will find the following:
[...] An alternative approach is using a two-way computed property with a setter:
<input v-model="message">
// ...
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
You can use the v-model to change, but you will need to register a computed property with a getter and a setter to change the state.
Works?
Works.
But let's say you have a form, you will need to make a getter and a setter to every input. This works, but isn't practical.
The best way to do it, in my opinion, is to use the principles of clean code to make it:
export function mapFields(options) {
const object = {};
for (let x = 0; x < options.fields.length; x++) {
const field = [options.fields[x]];
object[field] = {
get() {
return this.$store.state[options.base][field];
},
set(value) {
this.$store.commit(options.mutation, { [field]: value });
}
};
}
return object;
}
Where mapField is the function that map all the field and handle the form. Options is an object with a field which is the field you want to map and a base to refer.
At the end it will only return the getter and setter to us, not so different from before, but with a lot less code.
EDIT: I forgot to show how to use it, so here it is.
I would put it on some helper.js, so i can just import it from my userForm.vue, like this:
<script>
import { mapFields } from "@/helpers.js"
export default {
computed: {
...mapFields({
fields: ["name", "email", "street", "zipcode"],
base: "user",
mutation: "UPDATE_USER"
}),
...
Hope you enjoyed my first post here, any questions comment bellow! 😎
Top comments (13)
Thanks! This is exactly what I am looking for.
Where do you call the mapFields function. Could you please show an example?
I think if you do something like
...
Then, in your methods you define the 'handleSubmi function as follows:
methods:{
handleSubmit(e){
e.preventDefault();
mapFields(e)
//...
}
I think something like the above would do... what do you think?
I would use it in the computed property, so i could change the state as i input .
My fault, I will edit the post to answer you, sorry for this and thanks for asking.
Thank you! for this amazing super cool solution. I was searching the web for a normal not redundant way to deal with forms when using Vuex and thank god I bumped into this post. This is an amazing and easy solution, thanks.
p.s. there's a syntax error in the example 'const fields = [options.fields[x]]', the outer square brackets should be removed.
Awesome post, congrats gomito 🤘
Congratulation, it’s a great article!
Thanks man!
Lovely... lovely article. Thanks
Thanks for this elegant solution. But what about nested fields in base? It doesn't seem to be working for nested objects
This is awesome. Thank you.
WoW! Awesome! i was looking for some like that!!
can you show us your store?