2

I have some reusable components:

  • TextField
  • Form

And a component where I import them both. I pass the TextField component as props to the Form. In this Form component I have a submit button which needs to get all the values from the passed TextField components. As far as I could read in the docs I could use the v-model to get the values. But for some reason I can't find how to get those values in my Form component. Maybe I am missing something and I hope someone can help me with it. I already took a look at this question: Get all Input values - Vuejs. However, this didn't solve my problem.

The TextField component looks like this:

<template>
  <v-text-field
    v-model="vModel"
    :rules="rules"
    :counter="counter"
    :label="label"
    :required="required"
    :placeholder="placeholder"
    :value="value"
  ></v-text-field>
</template>

<script>
export default {
  name: "TextField",
  props: {
    rules: Array,
    counter: Number,
    label: String,
    required: {
      type: Boolean,
      default: true
    },
    placeholder: String,
    value: String
  },
  data: () => ({
    vModel: '',
  }),
};
</script>

The Form component looks like this:

<template>
  <v-form>
    <v-container>
      <slot></slot>
      <v-btn class="mr-4" @click="submit">Submit</v-btn>
    </v-container>
  </v-form>
</template>

<script>
export default {
  methods: {
    submit () {
      // console.log form data
    }
  }
};
</script>

And the component where I import both components:

<template>
  <Form>
      <v-row>
        <v-col cols="12" md="4">
          <TextField :label="'Email address'" :vModel="email"/>
        </v-col>
      </v-row>
  </Form>
</template>

<script>
import Form from "../../../components/Form/Form";
import TextField from "../../../components/Form/TextField";

export default {
  components: {
    Form,
    TextField,
  },
  data: () => ({
    email: '',
  })
};
</script>

I also created a CodeSandBox.

Can anyone give me some advice on how I might get the v-model values from the TextField components inside the Form component? If it's not possible, or I might do this better in another way please let me know.

2
  • I'm no vuejs/vuetify expert - but the :vModel="email" doesn't look like any syntax I've ever seen Commented Dec 6, 2019 at 9:21
  • 1
    I looked at your sandbox as well. You would have to pass the data as a prop to the form component as well to submit it from there: codesandbox.io/s/late-forest-7pd8q Commented Dec 6, 2019 at 9:30

2 Answers 2

1

v-model is simply a shorthand to create two things:

  • a :value binding (passed as a prop to your component)
  • a @input event handler

Currently, the vModel variable in your TextField component may receive the value, but it does not send it back to the parent component.

You could try something like this:

TextField

<template>
  <v-text-field
    v-model="localValue"
    :rules="rules"
    :counter="counter"
    :label="label"
    :required="required"
    :placeholder="placeholder"
  ></v-text-field>
</template>

<script>
export default {
  name: "TextField",
  props: {
    rules: Array,
    counter: Number,
    label: String,
    required: {
      type: Boolean,
      default: true
    },
    placeholder: String,
    value: String
  },
  data: () => ({
    localValue: '',
  }),
  created() {
    this.localValue = this.value;
    this.$watch('localValue', (value) => {
       this.$emit('input', value);
    }
  }
};
</script>

Form

<template>
  <v-form>
    <v-container>
      <slot></slot>
      <v-btn class="mr-4" @click="submit">Submit</v-btn>
    </v-container>
  </v-form>
</template>

<script>
export default {
  props: ['form'],
  methods: {
    submit () {
      alert(JSON.stringify(this.form));
    }
  }
};
</script>

Your final component:

<template>
  <Form :form="form">
      <v-row>
        <v-col cols="12" md="4">
          <TextField :label="'Email address'" v-model="[email protected]"/>
        </v-col>
      </v-row>
  </Form>
</template>

<script>
import Form from "../../../components/Form/Form";
import TextField from "../../../components/Form/TextField";

export default {
  components: {
    Form,
    TextField,
  },
  data: () => ({
    form: {
      email: ''
    }
  })
};
</script>

More information on v-model: https://v2.vuejs.org/v2/guide/forms.html

Sign up to request clarification or add additional context in comments.

4 Comments

Take a look at the sandbox I created: codesandbox.io/s/late-forest-7pd8q. Also, you might want to namespace your form data to pass it around easily: codesandbox.io/s/condescending-kepler-9c40q
I don't know why but if I copy that code into my own project it alerts undefined. I am trying to figure out why but your sandbox works like how I want it to work.
Make sure you pass the data as props to the form component in your final component. I updated my answer to reflect these changes.
Thank you very much! It works now, completely forgot to pass the data
1

Not exactly sure as to what you doing in your code, but to simplify the template and component with v-model would look something like the code below.

ContactUs.vue


<template>     
    <form method="POST"
          autocomplete="off"
          class="form--container relative box-col-center w-full"
          name="contact"
          action="/form/contact"
          @submit.prevent="onSubmit">

        <input class="form--field font-poppins w-full"
               type="text"
               name="name"
               v-model="field.name"
               placeholder="Your name"
               autocomplete='name'>

        <input class="form--field font-poppins w-full"
               type="email"
               id="email"
               name="email"
               v-model="field.email"
               placeholder="Your email"
               autocomplete='email'>

        <textarea class="textarea form--field font-poppins w-full"
              id="body"
              name="body"
              placeholder="I'd like to know about ..."
              v-model="field.body"
              rows="5">
            </textarea>

        <button type="submit"
                @click.prevent="onSubmit()"
                class="container--row container--center btn--purple btn--040 w-2/3 lg:w-full">
            <span class="text--w-full uppercase">Submit</span>
        </button>

    </form>
</template>

<script>

    export default {
        name: 'ContactUs',
        data() {
            return {
                fields:{
                    name: '',
                    email: '',
                    body: ''
                },
            }
        },
        methods: {
            onSubmit() {
                let vm = this;

                return new Promise((resolve, reject) => {
                    axios.post('/forms/contact', vm.fields)
                        .then(response => {
                            resolve(response.data);

                        }).catch(err => {
                            reject(err.response);
                    });
                });
            },
        }
    }
</script>


If you are attempting to create a Form service class then it would almost the same, except you would abstract the form logic to that class.

FormService.js


export default class Form {
    /**
     * Create a new Form instance.
     *
     * @param {object} data
     * @param type
     */
    constructor(data) {
        this.originalData = data;
        for (let field in data) {
            this[field] = data[field];
        }
    }

    /**
     * Submit the form.
     *
     * @param {string} requestType
     * @param {string} url
     */
    submit(requestType, url) {
        return new Promise((resolve, reject) => {
            axios[requestType](url, this.data())
                .then(response => {
                      resolve(response.data);

                }).catch(err => {
                    reject(err.response);
                });
        });
    }

}

and then in your component, you would inject the form services and use the data

ContactUs.vue

    import Form from '../services/FormService.js';

    export default {
        name: 'ContactUs',

        data() {
            return {
                fields: new Form({
                    name: '',
                    email: '',
                    body: ''
                }),
            }
        },
        methods: {
            onSubmit() {
                let self = this;

                self.form.post('/forms/contact')
                    .then(response => {


                    }).catch((err) => {

                })
            },
         }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.