I'm trying to build a re-usable component to deal with submitting forms via AJAX using Vue.js. Ideally, what I want to do is have a generic component that can be used in place of a HTML form
element, in that may contain an unknown set of form elements such as input
, select
, textarea
and so on.
I have got the following code for my component which is named ajax-form
:
<template>
<form class="form" :action="action" :method="method" v-on:submit.prevent="ajaxSubmit">
<slot></slot>
</form>
</template>
<script>
module.exports = {
props: {
action: {
required: true,
type: String
},
method: {
default: 'post',
required: false,
type: String
}
},
data() {
return {
formData: {}
}
},
methods: {
ajaxSubmit() {
// Do ajax
}
}
}
</script>
And in my HTML, I would have something like the following:
<ajax-form action="http://example.com/do/something">
<input name="first_name" type="text">
<textarea name="about_you"></textarea>
</ajax-form>
What I would ideally like to happen is have all of the form elements that are placed inside my component using it's slot to be mapped to the data.formData
property in my Vue component instance. So in this case, the data
property would look like:
data: {
formData: {
first_name: '',
about: ''
}
}
If I was to add another field to the component in my HTML, I would expect that to also be mapped to the Vue instance's data
property.
Is there a way I can achieve this? Is there a way that I can tell Vue, when putting my form elements into the component via the slot, that I want this element to be mapped to something in the component's data
?
I have tried adding v-model
and v-bind
on each form element to see if it that would somehow pass the data into the component's data:
<ajax-form action="http://example.com/do/something">
<input name="first_name" type="text" v-model="formData.first_name">
</ajax-form>
However, Vue complains that reactive data properties must be declared before they're used in the template:
[Vue warn]: Property or method "formData" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Scoped slots To pass a property in Vue, you would define the data in the parent component and assign a value to the data. Then, you'd pass the value of the property to the child component so the data becomes a property in the child component.
How to use it. Using the slot is very easy, we should just write the <slot> component (which is a reserved word in Vue. js) inside the child component's template, where we want to receive data. A child component uses slot.
You can do this with scopedSlots.
The api looks like this:
<ajax-form action="http://example.com/do/something">
<template scope="{formData}">
<input name="first_name" type="text" v-model="formData.first_name">
</template>
</ajax-form>
And in the ajax-form
component:
<form class="form" :action="action" :method="method" v-on:submit.prevent="ajaxSubmit">
<slot :formData="formData">
</form>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With