<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="app">
New user:
<v-form :schema="formSchema" :data="formData"></v-form>
<hr>
Form data:
<pre>{{ formData | json }}</pre>
</div>
<!-- Scripts -->
<script data-require="vue.js@2.0.3" data-semver="2.0.3" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<script src="script.js"></script>
</body>
</html>
// Text input field component
const textInput = {
props: {
field: { required: true },
data: { required: true }
},
template: `
<div class="form-control">
<label>{{ field.label }}</label>
<input class="input" type="text" :placeholder="field.placeholder" v-model="data.value">
</div>
`
};
// Checkbox input field component
const checkboxInput = {
props: {
field: { required: true },
data: { required: true }
},
template: `
<div class="form-control">
<label>{{ field.label }}</label>
<label class="input">
<input type="checkbox" v-model="data.value">
{{ field.placeholder }}
</label>
</div>
`
};
// Dynamic form component
const vForm = {
template: `
<div class="VueForm">
<template v-for="field in schema.fields">
<component :is="field.type" :field="field" :data.sync="data[field.name]"></component>
</template>
</div>
`,
components: {
textInput: textInput,
checkboxInput: checkboxInput
},
props: {
schema: { required: true },
data: { required: true }
}
};
Vue.component('v-form', vForm);
// Root Vue instance
const app =new Vue({
el: '#app',
data: {
formSchema: {
fields: [
{
type: 'text-input',
name: 'first_name',
label: 'First name',
placeholder: 'Enter first name'
},
{
type: 'text-input',
name: 'last_name',
label: 'Last name',
placeholder: 'Enter last name'
},
{
type: 'checkbox-input',
name: 'is_admin',
label: 'Administrator',
placeholder: 'Sure, why not'
}
]
},
formData: {
first_name: {
value: 'John'
},
last_name: {
value: 'Doe'
},
is_admin: {
value: true
}
}
}
});
html, body {
font-family: sans-serif;
}
.form-control {
padding: 8px 16px;
}
.form-control label+.input {
display: block;
}
# Vue.js dynamic form example
This example demonstrates how simple dynamic forms can be implemented with vue.js
It's a very basic example of course just to show the idea behind it.
## How it works
The main "heavy lifter" of this concept is Vue's `<component :is="comp-name"></component>` component
that can dynamically render a component with provided component's element selector through `is` property.
Then the `<v-form>` component accepts a `schema` property (a definition of the form's "schema", or in other words - a description of how this form should be constructed),
and a `data` property that contains all of the form's data.
In the `<v-form` component we loop through the `schema`'s fields
and render each of them using Vue's `<component>` dynamic component.
We also provide a `field` and `data` properties on the `<component>` of each field so they're passed to the rendered field component itself
and there to be used to bind `v-model` and some other field related data (like label) to the field's input.
The result is a dynamic form that we can describe via the `schema` and fill with data without touching or creating new templates for each field of our form.
This allows for consistent forms that reuses the same markup for all of the fields throughout the application.