'Multiple forms with one submit() method by Vue

I have a few forms. Every of them have the same logic (validation, sending...) so, I want to create one method to control actions on my forms. For now my code is redundancy, because I have the same methods onSubmit() on every .vue file.

my HTML:

<div id="app">
    <myform-one></myform-one>
    <myform-two></myform-two>
</div>

my JavaScript (main.js - entry file in webpack):

import Vue from 'vue';
import Myform1 from './myform1.vue';
import Myform2 from './myform2.vue';

new Vue({
    el: '#app',
    components: {
        myformOne: Myform1,
        myformTwo: Myform2
    }
});

and VUE components files:

myform1.vue:

<template>
    <div>
        <form @submit.prevent="onSubmit">
            <input type="text" v-model="fields.fname11" />
            <input type="text" v-model="fields.fname12" />
            <button type="submit">submit</button>
        </form>
    </div>
</template>

<script>
    let formfields = {
        fname11: '',
        fname12: ''
    };

    export default {
        data() {
            return {
                fields: formfields
            }
        },

        methods: {
            onSubmit() {
                // code responsible for reading, validating and sending data here
                // ...
                console.log(this.fields);
            }
        },
    }
</script>

and myform2.vue:

<template>
    <div>
        <form @submit.prevent="onSubmit">
            <input type="text" v-model="fields.fname21" />
            <input type="text" v-model="fields.fname22" />
            <input type="text" v-model="fields.fname23" />
            <button type="submit">submit</button>
        </form>
    </div>
</template>

<script>
    let formfields = {
        fname21: '',
        fname22: '',
        fname23: '',
    };

    export default {
        data() {
            return {
                fields: formfields
            }
        },

        methods: {
            onSubmit() {
                // code responsible for reading, validating and sending data here
                // ...
                console.log(this.fields);
            }
        },
    }
</script>

How can I create and use one, common method submitForm()? And where its code should be (good practice)?



Solution 1:[1]

Create a separate file which contains the logic:

// submitForm.js
export default function (fields) {
   // code responsible for reading, validating and sending data here
   // ...
}

Then use that logic inside the components

import submitForm from "../services/submitForm.js"
...
methods: {
  onSubmit() {
    submitForm(this.fields)
  }
}

Solution 2:[2]

There are some options. My favorite is creating a mixin vue docs mixins

export const form_functionality = {
  methods: {
     on_submit() {
      //logic of submit
     },
     //here we can have other reusable methods
  }
}

Then in your components use that mixin as follow:

import { form_functionality } from 'path_of_mixin'
export default {
  mixins: [form_functionality]
}

In the end, what mixins has (created, methods, data etc) will be merged to the component which uses that mixin.

So, practically you can access the mixin method like this.on_submit()

Solution 3:[3]

Vue3 (with Quasar for me but I'm sure it would work for any framework):

Say you have a parent which contains a number of forms <Forms />:

First create a composable function like so useForms.js:

import { ref } from 'vue'

const forms = ref([])

export function useForms(){
  
  const checkForms = () => {
    forms.value.forEach((form) => form.validate()
  }  

  const addFormToFormsArray = (form) => {
    forms.value.push(form)
  }

  return { forms, addFormToFormsArray, checkForms }
}

Then import it into <Forms />:

<template>
  <Form />
  <Form />
  <Form />
  <button @click="checkForms">Check Form</button>
</template>

<script setup>
import { useForms } from '../useForms';

const { checkForms } = useForms()
</script>

Finally, inside the <Form />:

<template>
  <form ref="form">
    .../stuff
  </form>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useForms } from '../useForms';

const form = ref(null)

onMounted(() => {
  addFormToFormsArray(form.value)
})

const { checkForms, addFormToFormsArray } = useForms()
</script>

When performing the check function in the parent, it should go through each form and check for any issues.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bob Fanger
Solution 2
Solution 3 Riza Khan