Skip to content

Commit 3f52a20

Browse files
author
Lionel Bijaoui
committed
Rework of formGenerator to use a component
Allow HTML for label & hint
1 parent 26960e6 commit 3f52a20

File tree

5 files changed

+332
-273
lines changed

5 files changed

+332
-273
lines changed

src/formGenerator.vue

Lines changed: 9 additions & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,24 @@
22
div.vue-form-generator(v-if='schema != null')
33
fieldset(v-if="schema.fields", :is='tag')
44
template(v-for='field in fields')
5-
.form-group(v-if='fieldVisible(field)', :class='getFieldRowClasses(field)')
6-
label(v-if="fieldTypeHasLabel(field)", :for="getFieldID(field)", :class="field.labelClasses")
7-
| {{ field.label }}
8-
span.help(v-if='field.help')
9-
i.icon
10-
.helpText(v-html='field.help')
11-
.field-wrap
12-
component(:is='getFieldType(field)', :disabled='fieldDisabled(field)', :model='model', :schema='field', :formOptions='options', @model-updated='modelUpdated', @validated="onFieldValidated")
13-
.buttons(v-if='buttonVisibility(field)')
14-
button(v-for='btn in field.buttons', @click='buttonClickHandler(btn, field, $event)', :class='btn.classes') {{ btn.label }}
15-
.hint(v-if='field.hint') {{ fieldHint(field) }}
16-
.errors.help-block(v-if='fieldErrors(field).length > 0')
17-
span(v-for='(error, index) in fieldErrors(field)', v-html='error', track-by='index')
5+
form-group(v-if='fieldVisible(field)', :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated")
186

197
template(v-for='group in groups')
208
fieldset(:is='tag', :class='getFieldRowClasses(group)')
219
legend(v-if='group.legend') {{ group.legend }}
2210
template(v-for='field in group.fields')
23-
.form-group(v-if='fieldVisible(field)', :class='getFieldRowClasses(field)')
24-
label(v-if="fieldTypeHasLabel(field)", :for="getFieldID(field)", :class="field.labelClasses")
25-
| {{ field.label }}
26-
span.help(v-if='field.help')
27-
i.icon
28-
.helpText(v-html='field.help')
29-
.field-wrap
30-
component(:is='getFieldType(field)', :disabled='fieldDisabled(field)', :model='model', :schema='field', :formOptions='options',@model-updated='modelUpdated', @validated="onFieldValidated")
31-
.buttons(v-if='buttonVisibility(field)')
32-
button(v-for='btn in field.buttons', @click='buttonClickHandler(btn, field, $event)', :class='btn.classes') {{ btn.label }}
33-
.hint(v-if='field.hint') {{ field.hint }}
34-
.errors.help-block(v-if='fieldErrors(field).length > 0')
35-
span(v-for='(error, index) in fieldErrors(field)', v-html='error', track-by='index')
11+
form-group(v-if='fieldVisible(field)', :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated")
3612
</template>
3713

3814
<script>
39-
// import Vue from "vue";
40-
import { get as objGet, forEach, isFunction, isNil, isArray, isString } from "lodash";
41-
import { slugifyFormID } from "./utils/schema";
42-
43-
// Load all fields from '../fields' folder
44-
let fieldComponents = {};
45-
46-
let coreFields = require.context("./fields/core", false, /^\.\/field([\w-_]+)\.vue$/);
47-
48-
forEach(coreFields.keys(), key => {
49-
let compName = key.replace(/^\.\//, "").replace(/\.vue/, "");
50-
fieldComponents[compName] = coreFields(key).default;
51-
});
52-
53-
if (process.env.FULL_BUNDLE) {
54-
// eslint-disable-line
55-
let Fields = require.context("./fields/optional", false, /^\.\/field([\w-_]+)\.vue$/);
56-
57-
forEach(Fields.keys(), key => {
58-
let compName = key.replace(/^\.\//, "").replace(/\.vue/, "");
59-
fieldComponents[compName] = Fields(key).default;
60-
});
61-
}
15+
import { get as objGet, forEach, isFunction, isNil, isArray } from "lodash";
16+
import formMixin from "./formMixin.js";
17+
import formGroup from "./formGroup.vue";
6218
6319
export default {
64-
components: fieldComponents,
65-
20+
name: "formGenerator",
21+
components: { formGroup },
22+
mixins: [formMixin],
6623
props: {
6724
schema: Object,
6825
@@ -163,75 +120,6 @@ export default {
163120
},
164121
165122
methods: {
166-
// Get style classes of field
167-
getFieldRowClasses(field) {
168-
const hasErrors = this.fieldErrors(field).length > 0;
169-
let baseClasses = {
170-
[objGet(this.options, "validationErrorClass", "error")]: hasErrors,
171-
[objGet(this.options, "validationSuccessClass", "valid")]: !hasErrors,
172-
disabled: this.fieldDisabled(field),
173-
readonly: this.fieldReadonly(field),
174-
featured: this.fieldFeatured(field),
175-
required: this.fieldRequired(field)
176-
};
177-
178-
if (isArray(field.styleClasses)) {
179-
forEach(field.styleClasses, c => (baseClasses[c] = true));
180-
} else if (isString(field.styleClasses)) {
181-
baseClasses[field.styleClasses] = true;
182-
}
183-
184-
if (!isNil(field.type)) {
185-
baseClasses["field-" + field.type] = true;
186-
}
187-
188-
return baseClasses;
189-
},
190-
191-
// Get type of field 'field-xxx'. It'll be the name of HTML element
192-
getFieldType(fieldSchema) {
193-
return "field-" + fieldSchema.type;
194-
},
195-
196-
// Should field type have a label?
197-
fieldTypeHasLabel(field) {
198-
if (isNil(field.label)) return false;
199-
200-
let relevantType = "";
201-
if (field.type === "input") {
202-
relevantType = field.inputType;
203-
} else {
204-
relevantType = field.type;
205-
}
206-
207-
switch (relevantType) {
208-
case "button":
209-
case "submit":
210-
case "reset":
211-
return false;
212-
default:
213-
return true;
214-
}
215-
},
216-
217-
// Get disabled attr of field
218-
fieldDisabled(field) {
219-
if (isFunction(field.disabled)) return field.disabled.call(this, this.model, field, this);
220-
221-
if (isNil(field.disabled)) return false;
222-
223-
return field.disabled;
224-
},
225-
226-
// Get required prop of field
227-
fieldRequired(field) {
228-
if (isFunction(field.required)) return field.required.call(this, this.model, field, this);
229-
230-
if (isNil(field.required)) return false;
231-
232-
return field.required;
233-
},
234-
235123
// Get visible prop of field
236124
fieldVisible(field) {
237125
if (isFunction(field.visible)) return field.visible.call(this, this.model, field, this);
@@ -241,35 +129,6 @@ export default {
241129
return field.visible;
242130
},
243131
244-
// Get readonly prop of field
245-
fieldReadonly(field) {
246-
if (isFunction(field.readonly)) return field.readonly.call(this, this.model, field, this);
247-
248-
if (isNil(field.readonly)) return false;
249-
250-
return field.readonly;
251-
},
252-
253-
// Get featured prop of field
254-
fieldFeatured(field) {
255-
if (isFunction(field.featured)) return field.featured.call(this, this.model, field, this);
256-
257-
if (isNil(field.featured)) return false;
258-
259-
return field.featured;
260-
},
261-
262-
// Get current hint.
263-
fieldHint(field) {
264-
if (isFunction(field.hint)) return field.hint.call(this, this.model, field, this);
265-
266-
return field.hint;
267-
},
268-
269-
buttonClickHandler(btn, field, event) {
270-
return btn.onclick.call(this, this.model, field, event, this);
271-
},
272-
273132
// Child field executed validation
274133
onFieldValidated(res, errors, field) {
275134
// Remove old errors for this field
@@ -301,7 +160,7 @@ export default {
301160
302161
forEach(this.$children, child => {
303162
if (isFunction(child.validate)) {
304-
fields.push(child); // keep track of validated children
163+
fields.push(child.$refs.child); // keep track of validated children
305164
results.push(child.validate(true));
306165
}
307166
});
@@ -338,32 +197,12 @@ export default {
338197
forEach(this.$children, child => {
339198
child.clearValidationErrors();
340199
});
341-
},
342-
343-
modelUpdated(newVal, schema) {
344-
this.$emit("model-updated", newVal, schema);
345-
},
346-
347-
buttonVisibility(field) {
348-
return field.buttons && field.buttons.length > 0;
349-
},
350-
351-
fieldErrors(field) {
352-
let res = this.errors.filter(e => e.field === field);
353-
return res.map(item => item.error);
354-
},
355-
356-
getFieldID(schema) {
357-
const idPrefix = this.options && this.options.fieldIdPrefix ? this.options.fieldIdPrefix : "";
358-
return slugifyFormID(schema, idPrefix);
359200
}
360201
}
361202
};
362203
</script>
363204

364205
<style lang="scss">
365-
$errorColor: #f00;
366-
367206
.vue-form-generator {
368207
* {
369208
box-sizing: border-box;
@@ -499,64 +338,5 @@ $errorColor: #f00;
499338
font-style: italic;
500339
font-size: 0.8em;
501340
} // .hint
502-
503-
.form-group {
504-
display: inline-block;
505-
vertical-align: top;
506-
width: 100%;
507-
// margin: 0.5rem 0.26rem;
508-
margin-bottom: 1rem;
509-
510-
label {
511-
font-weight: 400;
512-
}
513-
514-
&.featured {
515-
> label {
516-
font-weight: bold;
517-
}
518-
}
519-
520-
&.required {
521-
> label:after {
522-
content: "*";
523-
font-weight: normal;
524-
color: Red;
525-
// position: absolute;
526-
padding-left: 0.2em;
527-
font-size: 1em;
528-
}
529-
}
530-
531-
&.disabled {
532-
> label {
533-
color: #666;
534-
font-style: italic;
535-
}
536-
}
537-
538-
&.error {
539-
input:not([type="checkbox"]),
540-
textarea,
541-
select {
542-
border: 1px solid $errorColor;
543-
background-color: rgba($errorColor, 0.15);
544-
}
545-
546-
.errors {
547-
color: $errorColor;
548-
font-size: 0.8em;
549-
span {
550-
display: block;
551-
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAiklEQVR4Xt2TMQoCQQxF3xdhu72MpZU3GU/meBFLOztPYrVWsQmEWSaMsIXgK8P8RyYkMjO2sAN+K9gTIAmDAlzoUzE7p4IFytvDCQWJKSStYB2efcAvqZFM0BcstMx5naSDYFzfLhh/4SmRM+6Agw/xIX0tKEDFufeDNRUc4XqLRz3qabVIf3BMHwl6Ktexn3nmAAAAAElFTkSuQmCC");
552-
background-repeat: no-repeat;
553-
padding-left: 17px;
554-
padding-top: 0px;
555-
margin-top: 0.2em;
556-
font-weight: 600;
557-
}
558-
} // .errors
559-
} // .error
560-
} // .form-group
561341
} // fieldset
562342
</style>

0 commit comments

Comments
 (0)