DEV Community

Matheus Gomes 👨‍💻
Matheus Gomes 👨‍💻

Posted on

How to make a form handling with vuex

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">
Enter fullscreen mode Exit fullscreen mode

If you try this you will see that:

  1. It doesn't work
  2. 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">
Enter fullscreen mode Exit fullscreen mode
// ...
computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

click here to see.

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;
}
Enter fullscreen mode Exit fullscreen mode

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"
    }),
...
Enter fullscreen mode Exit fullscreen mode

Hope you enjoyed my first post here, any questions comment bellow! 😎

Happy new year

Top comments (13)

Collapse
 
vamsigandra profile image
Vamsi

Thanks! This is exactly what I am looking for.
Where do you call the mapFields function. Could you please show an example?

Collapse
 
lilarmstrong profile image
Armstrong

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?

Collapse
 
matheusgomes062 profile image
Matheus Gomes 👨‍💻

I would use it in the computed property, so i could change the state as i input .

Collapse
 
matheusgomes062 profile image
Matheus Gomes 👨‍💻

My fault, I will edit the post to answer you, sorry for this and thanks for asking.

Collapse
 
mordechairoth profile image
mordechairoth

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.

Collapse
 
wakeupmh profile image
Marcos Henrique

Awesome post, congrats gomito 🤘

Collapse
 
themsiqueira profile image
Siqueira

Congratulation, it’s a great article!

Collapse
 
matheusgomes062 profile image
Matheus Gomes 👨‍💻

Thanks man!

Collapse
 
lilarmstrong profile image
Armstrong

Lovely... lovely article. Thanks

Collapse
 
unaimian profile image
U.N • Edited

Thanks for this elegant solution. But what about nested fields in base? It doesn't seem to be working for nested objects

Collapse
 
assoft profile image
Assoft

This is awesome. Thank you.

Collapse
 
dcruz1990 profile image
Dennis Quesada Cruz

WoW! Awesome! i was looking for some like that!!

Collapse
 
sergiosuramin profile image
sergiosuramin

can you show us your store?