Skip to content

Commit 85f6e21

Browse files
committed
Merge branch 'samples/fsfiddle-demo' into develop
* samples/fsfiddle-demo: jsfiddle-sample embedded into repo migrated VFG docs to newer GitBooks, created GitHub Repo for Docs to allow for easier maintenance, updated JSFiddle to use "latest" VFG, and created a CodePen version as well Codacy (guard-for-in) fix fixed code structure added "options" to VFG install function, appending custom "validators" to the validators object that are passed into `Vue.use(VueFormGenerator, { validators: { key: (value, field, model) => {} }) added an optional "unique" flag to "getFieldID" that appends lodash "uniqueId" to the ID when true. Fixes vue-generators#468 fixed single-quotes added "type" attribute to inside buttons schema, defaults to "button" when one is not provided fixes vue-generators#480 - dates are always passed to "date" and "datetime-local" elements using the standard format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss), and "datetime" elements are converted into "datetime-local" (datetime is deprecated/obsolete). added "item.disabled" logic, supporting both boolean values and a function that is passed a reference to the model to determine disabled logic based on the model. listen for model-updated from `fields`, and fix `debounceFormatFunction` property to match fieldInput's `debounceFormatFunc` instead. Fix required number input does not require a value
2 parents fa0a2ff + 5d2620b commit 85f6e21

File tree

14 files changed

+288
-19
lines changed

14 files changed

+288
-19
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ A schema-based form generator component for Vue.js.
1515

1616
## Demo
1717

18-
[JSFiddle simple example](https://jsfiddle.net/icebob/0mg1v81e/)
18+
[JSFiddle simple example](https://jsfiddle.net/zoul0813/d8excp36/)
19+
[CodePen simple example](https://codepen.io/zoul0813/pen/OrNVNw)
1920

20-
[![Screenshot](https://icebob.gitbooks.io/vueformgenerator/content/assets/vfg-example1.png)](https://jsfiddle.net/icebob/0mg1v81e/)
21+
[![Screenshot](https://github.com/vue-generators/vue-form-generator-docs/raw/master/assets/vfg-example1.png)](https://jsfiddle.net/zoul0813/d8excp36/)
2122

2223
## Features
2324

@@ -33,7 +34,7 @@ A schema-based form generator component for Vue.js.
3334

3435
## Documentation
3536

36-
[Online documentation on Gitbook](https://icebob.gitbooks.io/vueformgenerator/content/)
37+
[Online documentation on Gitbook](https://vue-generators.gitbook.io/vue-generators/)
3738

3839
## Dependencies
3940

@@ -43,7 +44,7 @@ While built-in fields don't need external dependencies, optional fields may need
4344
These dependencies fall into two camps: jQuery or Vanilla. You can find almost the same functionality in both flavors.
4445
In the end, it's your choice to depend on jQuery or not.
4546

46-
You can find details about dependencies in the official [documentation](https://icebob.gitbooks.io/vueformgenerator/content/) under each specific component.
47+
You can find details about dependencies in the official [documentation](https://vue-generators.gitbook.io/vue-generators/) under each specific component.
4748

4849
## Installation
4950

examples/jsfiddle-sample/demo.css

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
html {
2+
font-family: Tahoma;
3+
font-size: 14px;
4+
}
5+
6+
body {
7+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
8+
font-size: 14px;
9+
line-height: 1.42857143;
10+
color: #333;
11+
}
12+
13+
pre {
14+
overflow: auto;
15+
}
16+
pre .string { color: #885800; }
17+
pre .number { color: blue; }
18+
pre .boolean { color: magenta; }
19+
pre .null { color: red; }
20+
pre .key { color: green; }
21+
22+
h1 {
23+
text-align: center;
24+
font-size: 36px;
25+
margin-top: 20px;
26+
margin-bottom: 10px;
27+
font-weight: 500;
28+
}
29+
30+
fieldset {
31+
border: 0;
32+
}
33+
34+
.panel {
35+
margin-bottom: 20px;
36+
background-color: #fff;
37+
border: 1px solid transparent;
38+
border-radius: 4px;
39+
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
40+
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
41+
border-color: #ddd;
42+
}
43+
44+
.panel-heading {
45+
color: #333;
46+
background-color: #f5f5f5;
47+
border-color: #ddd;
48+
49+
padding: 10px 15px;
50+
border-bottom: 1px solid transparent;
51+
border-top-left-radius: 3px;
52+
border-top-right-radius: 3px;
53+
}
54+
55+
.panel-body {
56+
padding: 15px;
57+
}
58+
59+
.field-checklist .wrapper {
60+
width: 100%;
61+
}

examples/jsfiddle-sample/demo.details

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
name: vue-form-generator example
3+
description: https://github.com/vue-generators/vue-form-generator
4+
authors:
5+
- David Higgins (@zoul0813)
6+
- Icebob (@icebob)
7+
resources:
8+
- https://unpkg.com/[email protected]/dist/vue.min.js
9+
- https://unpkg.com/vue-form-generator
10+
- https://unpkg.com/vue-form-generator/dist/vfg.css
11+
normalize_css: no
12+
load_type: l
13+
...

examples/jsfiddle-sample/demo.html

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<h1 class="text-center">Demo of vue-form-generator</h1>
2+
<div class="container" id="app">
3+
<div class="panel panel-default">
4+
<div class="panel-heading">Form</div>
5+
<div class="panel-body">
6+
<vue-form-generator :schema="schema" :model="model" :options="formOptions"></vue-form-generator>
7+
</div>
8+
</div>
9+
10+
<div class="panel panel-default">
11+
<div class="panel-heading">Model</div>
12+
<div class="panel-body">
13+
<pre v-if="model" v-html="prettyJSON(model)"></pre>
14+
</div>
15+
</div>
16+
17+
<div class="panel panel-default">
18+
<div class="panel-heading">Schema</div>
19+
<div class="panel-body">
20+
<pre v-if="model" v-html="prettyJSON(schema)"></pre>
21+
</div>
22+
</div>
23+
</div>

examples/jsfiddle-sample/demo.js

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
var vm = new Vue({
2+
el: "#app",
3+
4+
components: {
5+
"vue-form-generator": VueFormGenerator.component
6+
},
7+
8+
data() {
9+
return {
10+
model: {
11+
id: 1,
12+
name: "John Doe",
13+
password: "J0hnD03!x4",
14+
age: 35,
15+
skills: ["Javascript", "VueJS"],
16+
17+
status: true
18+
},
19+
schema: {
20+
fields: [{
21+
type: "input",
22+
inputType: "text",
23+
label: "ID",
24+
model: "id",
25+
readonly: true,
26+
featured: false,
27+
disabled: true
28+
}, {
29+
type: "input",
30+
inputType: "text",
31+
label: "Name",
32+
model: "name",
33+
readonly: false,
34+
featured: true,
35+
required: true,
36+
disabled: false,
37+
placeholder: "User's name",
38+
validator: VueFormGenerator.validators.string
39+
}, {
40+
type: "input",
41+
inputType: "password",
42+
label: "Password",
43+
model: "password",
44+
min: 6,
45+
required: true,
46+
hint: "Minimum 6 characters",
47+
validator: VueFormGenerator.validators.string
48+
}, {
49+
type: "input",
50+
inputType: "number",
51+
label: "Age",
52+
model: "age",
53+
min: 18,
54+
validator: VueFormGenerator.validators.number
55+
}, {
56+
type: "input",
57+
inputType: "email",
58+
label: "E-mail",
59+
model: "email",
60+
placeholder: "User's e-mail address",
61+
validator: VueFormGenerator.validators.email
62+
}, {
63+
type: "checklist",
64+
label: "Skills",
65+
model: "skills",
66+
multi: true,
67+
required: true,
68+
multiSelect: true,
69+
values: ["HTML5", "Javascript", "CSS3", "CoffeeScript", "AngularJS", "ReactJS", "VueJS"]
70+
}, {
71+
type: "switch",
72+
label: "Status",
73+
model: "status",
74+
multi: true,
75+
readonly: false,
76+
featured: false,
77+
disabled: false,
78+
default: true,
79+
textOn: "Active",
80+
textOff: "Inactive"
81+
}]
82+
},
83+
84+
formOptions: {
85+
validateAfterLoad: true,
86+
validateAfterChanged: true
87+
}
88+
};
89+
},
90+
91+
methods: {
92+
prettyJSON: function(json) {
93+
if (json) {
94+
json = JSON.stringify(json, undefined, 4);
95+
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
96+
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
97+
var cls = 'number';
98+
if (/^"/.test(match)) {
99+
if (/:$/.test(match)) {
100+
cls = 'key';
101+
} else {
102+
cls = 'string';
103+
}
104+
} else if (/true|false/.test(match)) {
105+
cls = 'boolean';
106+
} else if (/null/.test(match)) {
107+
cls = 'null';
108+
}
109+
return '<span class="' + cls + '">' + match + '</span>';
110+
});
111+
}
112+
}
113+
},
114+
});

src/fields/abstractField.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { get as objGet, forEach, isFunction, isString, isArray, debounce } from "lodash";
1+
import { get as objGet, forEach, isFunction, isString, isArray, debounce, uniqueId } from "lodash";
22
import validators from "../utils/validators";
33
import { slugifyFormID } from "../utils/schema";
44

@@ -31,7 +31,7 @@ export default {
3131
return {
3232
errors: [],
3333
debouncedValidateFunc: null,
34-
debouncedFormatFunction: null
34+
debouncedFormatFunc: null
3535
};
3636
},
3737

@@ -208,9 +208,9 @@ export default {
208208
}
209209
},
210210

211-
getFieldID(schema) {
211+
getFieldID(schema, unique = false) {
212212
const idPrefix = objGet(this.formOptions, "fieldIdPrefix", "");
213-
return slugifyFormID(schema, idPrefix);
213+
return slugifyFormID(schema, idPrefix) + (unique ? "-" + uniqueId() : "");
214214
},
215215

216216
getFieldClasses() {

src/fields/core/fieldChecklist.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
.listbox.form-control(v-if="schema.listBox", :disabled="disabled")
44
.list-row(v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
55
label
6-
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
6+
input(:id="getFieldID(schema, true)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
77
| {{ getItemName(item) }}
88

99
.combobox.form-control(v-if="!schema.listBox", :disabled="disabled")
@@ -14,7 +14,7 @@
1414
.dropList
1515
.list-row(v-if="comboExpanded", v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
1616
label
17-
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
17+
input(:id="getFieldID(schema, true)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
1818
| {{ getItemName(item) }}
1919
</template>
2020

src/fields/core/fieldInput.vue

+31-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
.wrapper(v-attributes="'wrapper'")
33
input.form-control(
44
:id="getFieldID(schema)",
5-
:type="schema.inputType.toLowerCase()",
5+
:type="inputType",
66
:value="value",
77
@input="onInput",
88
@blur="onBlur",
@@ -53,6 +53,16 @@ const DATETIME_FORMATS = {
5353
5454
export default {
5555
mixins: [abstractField],
56+
computed: {
57+
inputType() {
58+
if(this.schema && this.schema.inputType === "datetime") {
59+
// convert "datetime" to "datetime-local" (datetime deprecated in favor of "datetime-local")
60+
// ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime
61+
return "datetime-local";
62+
}
63+
return this.schema.inputType;
64+
}
65+
},
5666
methods: {
5767
formatValueToModel(value) {
5868
if (value != null) {
@@ -71,6 +81,15 @@ export default {
7181
7282
return value;
7383
},
84+
formatValueToField(value) {
85+
switch(this.schema.inputType.toLowerCase()) {
86+
case "date":
87+
case "datetime":
88+
case "datetime-local":
89+
return this.formatDatetimeValueToField(value);
90+
}
91+
return value;
92+
},
7493
formatDatetimeToModel(newValue, oldValue) {
7594
let defaultFormat = DATETIME_FORMATS[this.schema.inputType.toLowerCase()];
7695
let m = fecha.parse(newValue, defaultFormat);
@@ -83,6 +102,17 @@ export default {
83102
}
84103
this.updateModelValue(newValue, oldValue);
85104
},
105+
formatDatetimeValueToField(value) {
106+
let defaultFormat = DATETIME_FORMATS[this.schema.inputType.toLowerCase()];
107+
let m = value;
108+
if(!isNumber(value)) {
109+
m = fecha.parse(value, defaultFormat);
110+
}
111+
if(m !== false) {
112+
return fecha.format(m, defaultFormat);
113+
}
114+
return value;
115+
},
86116
formatNumberToModel(newValue, oldValue) {
87117
if (!isNumber(newValue)) {
88118
newValue = NaN;

src/fields/core/fieldRadios.vue

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<template lang="pug">
22
.radio-list(:disabled="disabled", v-attributes="'wrapper'")
33
label(v-for="item in items", :class="{'is-checked': isItemChecked(item)}", v-attributes="'label'")
4-
input(:id="getFieldID(schema)", type="radio", :disabled="disabled", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses", :required="schema.required", v-attributes="'input'")
4+
input(:id="getFieldID(schema, true)", type="radio", :disabled="isItemDisabled(item)", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses", :required="schema.required", v-attributes="'input'")
55
| {{ getItemName(item) }}
66

77
</template>
88

99
<script>
10-
import { isObject } from "lodash";
10+
import { isObject, isFunction, get as objGet } from "lodash";
1111
import abstractField from "../abstractField";
1212
1313
export default {
@@ -64,6 +64,16 @@ export default {
6464
isItemChecked(item) {
6565
let currentValue = this.getItemValue(item);
6666
return currentValue === this.value;
67+
},
68+
isItemDisabled(item) {
69+
if (this.disabled) {
70+
return true;
71+
}
72+
let disabled = objGet(item, "disabled", false);
73+
if (isFunction(disabled)) {
74+
return disabled(this.model);
75+
}
76+
return disabled;
6777
}
6878
}
6979
};

src/formGenerator.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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)', :vfg="vfg", :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated")
5+
form-group(v-if='fieldVisible(field)', :vfg="vfg", :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated", @model-updated="onModelUpdated")
66

77
template(v-for='group in groups')
88
fieldset(:is='tag', :class='getFieldRowClasses(group)')

0 commit comments

Comments
 (0)