DEV Community

loading...

How to make a form handling with vuex

matheusgomes062 profile image Matheus Gomes πŸ‘¨β€πŸ’» ・2 min read

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

Discussion

pic
Editor guide
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 πŸ‘¨β€πŸ’» Author

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

Collapse
matheusgomes062 profile image
Matheus Gomes πŸ‘¨β€πŸ’» Author

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

Collapse
wakeupmh profile image
Marcos Henrique

Awesome post, congrats gomito 🀘

Collapse
lilarmstrong profile image
Armstrong

Lovely... lovely article. Thanks

Collapse
themsiqueira profile image
Mateus Siqueira

Congratulation, it’s a great article!

Collapse
matheusgomes062 profile image
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
unaimian profile image
U.N

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