Skip to content

Commit de3a5db

Browse files
committed
feat: add form builder
1 parent 5d2d749 commit de3a5db

File tree

2 files changed

+194
-2
lines changed

2 files changed

+194
-2
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<template>
2+
<div class="vue-form-builder">
3+
<vue-form
4+
ref="form"
5+
:model="clonedModel"
6+
:label-position="options.labelPosition"
7+
:label-width="options.labelWidth"
8+
data-vv-scope="form-1"
9+
>
10+
<vue-form-item
11+
v-for="(field, index) in schema.fields"
12+
:key="field.label + index"
13+
:label="field.label"
14+
:field="field.model"
15+
>
16+
<!-- Input -->
17+
<template
18+
v-if="field.type === 'input'"
19+
>
20+
<vue-input
21+
:key="field.name + index"
22+
:ref="field.name"
23+
v-model="clonedModel[field.model]"
24+
v-validate="field.validate"
25+
:type="field.inputType"
26+
:name="field.name"
27+
:readonly="field.readonly"
28+
:placeholder="field.placeholder"
29+
:disabled="field.disabled"
30+
@input="onUpdate"
31+
/>
32+
</template>
33+
<!-- Select -->
34+
<template v-if="field.type === 'select'">
35+
<vue-select
36+
v-model="clonedModel[field.model]"
37+
v-validate="field.validate"
38+
:data="field.options"
39+
:name="field.name"
40+
:placeholder="field.placeholder"
41+
:multiple="Array.isArray(clonedModel[field.model])"
42+
@change="onUpdate"
43+
>
44+
<vue-option
45+
v-for="i in field.options"
46+
:key="i.value"
47+
:value="i.value"
48+
:label="i.label"
49+
/>
50+
</vue-select>
51+
</template>
52+
<!-- Checkbox -->
53+
<template v-if="field.type === 'checkbox'">
54+
<vue-checkbox-group
55+
v-if="Array.isArray(clonedModel[field.model])"
56+
v-model="clonedModel[field.model]"
57+
v-validate="field.validate"
58+
:name="field.name"
59+
@change="onUpdate"
60+
>
61+
<vue-checkbox
62+
v-for="i in field.options"
63+
:key="i.value"
64+
:value="i.value"
65+
:label="i.label"
66+
/>
67+
</vue-checkbox-group>
68+
<vue-checkbox
69+
v-else
70+
v-model="clonedModel[field.model]"
71+
v-validate="field.validate"
72+
:name="field.name"
73+
:label="field.checkboxLabel"
74+
@change="onUpdate"
75+
/>
76+
</template>
77+
<!-- Radio -->
78+
<template v-if="field.type === 'radio'">
79+
<vue-radio
80+
v-for="i in field.options"
81+
:key="i.value"
82+
v-model="clonedModel[field.model]"
83+
v-validate="field.validate"
84+
:name="field.name"
85+
:value="i.value"
86+
:label="i.label"
87+
@change="onUpdate"
88+
/>
89+
</template>
90+
<!-- Actions -->
91+
<template v-if="field.type === 'actions'">
92+
<vue-button
93+
v-for="(i, idx) in field.buttons"
94+
:key="idx"
95+
:type="i.buttonType"
96+
@click="onAction(i.type)"
97+
>
98+
{{ i.buttonLabel }}
99+
</vue-button>
100+
</template>
101+
</vue-form-item>
102+
</vue-form>
103+
</div>
104+
</template>
105+
106+
<script>
107+
import Form from '../form/Form'
108+
import FormItem from '../form/FormItem'
109+
import Input from '../input/Input'
110+
import Checkbox from '../checkbox/Checkbox'
111+
import CheckboxGroup from '../checkbox/CheckboxGroup'
112+
import Radio from '../radio/Radio'
113+
import Select from '../select/Select'
114+
import Option from '../select/Option'
115+
import Button from '../button/Button'
116+
import { cloneShallow } from '@/utils'
117+
118+
export default {
119+
name: 'VueFormBuilder',
120+
121+
components: {
122+
VueForm: Form,
123+
VueFormItem: FormItem,
124+
VueInput: Input,
125+
VueCheckbox: Checkbox,
126+
VueCheckboxGroup: CheckboxGroup,
127+
VueRadio: Radio,
128+
VueSelect: Select,
129+
VueOption: Option,
130+
VueButton: Button
131+
},
132+
133+
model: {
134+
prop: 'model',
135+
event: 'update'
136+
},
137+
138+
props: {
139+
model: {
140+
type: Object,
141+
default: () => {}
142+
},
143+
schema: {
144+
type: Object,
145+
default: () => {}
146+
},
147+
options: {
148+
type: Object,
149+
default: () => {
150+
return {
151+
labelPosition: undefined,
152+
labelWidth: undefined
153+
}
154+
}
155+
}
156+
},
157+
158+
data () {
159+
return {
160+
clonedModel: {}
161+
}
162+
},
163+
164+
created () {
165+
this.clonedModel = cloneShallow(this.model)
166+
},
167+
168+
mounted () {
169+
// Hack to update validation
170+
this.$forceUpdate()
171+
},
172+
173+
methods: {
174+
isSelectMultiple (value) {
175+
return Array.isArray(value)
176+
},
177+
onUpdate () {
178+
this.$emit('update', this.clonedModel)
179+
},
180+
onAction (e) {
181+
this.$emit('action', { type: e, form: this.$refs.form })
182+
}
183+
}
184+
}
185+
</script>
186+
187+
<style lang="scss">
188+
189+
</style>

src/components/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Option from './select/Option.vue'
88
import Form from './form/Form.vue'
99
import FormItem from './form/FormItem.vue'
1010
import VeeValidate from 'vee-validate'
11+
import FormBuilder from './from-builder/FormBuilder.vue'
1112

1213
const components = [
1314
Input,
@@ -18,7 +19,8 @@ const components = [
1819
Select,
1920
Option,
2021
Form,
21-
FormItem
22+
FormItem,
23+
FormBuilder
2224
]
2325

2426
export default {
@@ -48,5 +50,6 @@ export {
4850
Select,
4951
Option,
5052
Form,
51-
FormItem
53+
FormItem,
54+
FormBuilder
5255
}

0 commit comments

Comments
 (0)