Skip to content

Commit 8a721d4

Browse files
committed
Impove code. Add built-in validators
1 parent a81bf42 commit 8a721d4

10 files changed

+531
-109
lines changed

build/webpack.build.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ module.exports = [
4949
libraryTarget: "umd"
5050
},
5151
plugins: [
52-
new webpack.optimize.UglifyJsPlugin,
52+
new webpack.optimize.UglifyJsPlugin({
53+
compress: {
54+
warnings: false
55+
}
56+
}),
5357
new webpack.BannerPlugin(banner, {
5458
raw: true
5559
})],

dist/vue-form-generator.js

+264-68
Large diffs are not rendered by default.

dist/vue-form-generator.min.js

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/simple/index.html

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
<body>
2929
<h1 class="text-center">Demo of vue-form-generator</h1>
3030
<div class="container" id="app">
31-
<vue-form-generator :schema="schema", :model="model"></vue-form-generator>
31+
<div class="panel panel-default">
32+
<div class="panel-heading">Form</div>
33+
<div class="panel-body">
34+
<vue-form-generator :schema="schema", :model="model", :options="formOptions"></vue-form-generator>
35+
</div>
36+
</div>
3237

3338
<div class="panel panel-default">
3439
<div class="panel-heading">Model</div>

examples/simple/main.js

+16-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var vm = new Vue({
22
el: "#app",
33
components: {
4-
"vue-form-generator": window.VueFormGenerator
4+
"vue-form-generator": VueFormGenerator.component
55
},
66

77
filters: {
@@ -58,18 +58,24 @@ var vm = new Vue({
5858
featured: true,
5959
required: true,
6060
disabled: false,
61-
placeholder: "User's name"
61+
placeholder: "User's name",
62+
validator: VueFormGenerator.validators.string
6263
},
6364
{
6465
type: "password",
6566
label: "Password",
66-
model: "password"
67+
model: "password",
68+
min: 6,
69+
required: true,
70+
hint: "Minimum 6 characters",
71+
validator: VueFormGenerator.validators.string
6772
},
6873
{
6974
type: "email",
7075
label: "E-mail",
7176
model: "email",
72-
placeholder: "User's e-mail address"
77+
placeholder: "User's e-mail address",
78+
validator: VueFormGenerator.validators.email
7379
},
7480
{
7581
type: "checklist",
@@ -85,7 +91,7 @@ var vm = new Vue({
8591
"CoffeeScript",
8692
"AngularJS",
8793
"ReactJS",
88-
"VueJS",
94+
"VueJS"
8995
]
9096
},
9197
{
@@ -99,6 +105,11 @@ var vm = new Vue({
99105
default: true
100106
}
101107
]
108+
},
109+
110+
formOptions: {
111+
validateAfterLoad: true,
112+
validateAfterChanged: true
102113
}
103114
}
104115
});

src/fields/fieldChecklist.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
.info {{ selectedCount }} selected
1111
.arrow
1212

13-
.dropList()
13+
.dropList
1414
.list-row(v-if="comboExpanded", v-for="item in items")
1515
label
1616
input(type="checkbox", :checked="getItemIsChecked(item)", @change="onChanged($event, item)")
@@ -134,7 +134,7 @@
134134
135135
.dropList {
136136
transition: height 0.5s;
137-
margin-top: 0.5em;
137+
//margin-top: 0.5em;
138138
}
139139
}
140140
</style>

src/formGenerator.vue

+23-26
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
<template lang="jade">
2-
.panel.panel-default
3-
.panel-heading Properties
4-
.panel-body
5-
table
6-
thead
7-
tbody
8-
tr(v-for="field in fields", v-if="fieldVisible(field)", :class="getFieldRowClasses(field)")
9-
td
10-
span.help(v-if="field.help")
11-
i.fa.fa-question-circle
12-
.helpText {{{field.help}}}
13-
14-
|{{ field.label }}
15-
td
16-
.field-wrap
17-
component(:is="getFieldType(field)", :disabled="fieldDisabled(field)", :model.sync="model", :schema.sync="field")
18-
.buttons(v-if="field.buttons && field.buttons.length > 0")
19-
button.btn.btn-default(v-for="btn in field.buttons", @click="btn.onclick(model, field)", :class="btn.classes") {{ btn.label }}
20-
.hint(v-if="field.hint") {{ field.hint }}
21-
.errors(v-if="field.errors && field.errors.length > 0")
22-
span(v-for="error in field.errors") {{ error }}
2+
table
3+
thead
4+
tbody
5+
tr(v-for="field in fields", v-if="fieldVisible(field)", :class="getFieldRowClasses(field)")
6+
td
7+
span.help(v-if="field.help")
8+
i.fa.fa-question-circle
9+
.helpText {{{field.help}}}
10+
11+
|{{ field.label }}
12+
td
13+
.field-wrap
14+
component(:is="getFieldType(field)", :disabled="fieldDisabled(field)", :model.sync="model", :schema.sync="field")
15+
.buttons(v-if="field.buttons && field.buttons.length > 0")
16+
button.btn.btn-default(v-for="btn in field.buttons", @click="btn.onclick(model, field)", :class="btn.classes") {{ btn.label }}
17+
.hint(v-if="field.hint") {{ field.hint }}
18+
.errors(v-if="field.errors && field.errors.length > 0")
19+
span(v-for="error in field.errors") {{ error }}
2320
</template>
2421

2522
<script>
@@ -48,7 +45,7 @@
4845
4946
data () {
5047
return {
51-
errors: []
48+
errors: [] // Validation errors
5249
}
5350
},
5451
@@ -65,19 +62,19 @@
6562
},
6663
6764
watch: {
68-
// Futás közbeni rekord váltáskor
65+
// new model loaded
6966
model: function() {
7067
if (this.options.validateAfterLoad === true && !this.isNewModel)
71-
this.$parent.validateForm();
68+
this.validate();
7269
else
7370
this.clearValidationErrors();
7471
}
7572
},
7673
7774
ready() {
78-
// Legelső betöltés
75+
// First load
7976
if (this.options && this.options.validateAfterLoad === true && !this.isNewModel)
80-
this.$parent.validateForm();
77+
this.validate();
8178
else
8279
this.clearValidationErrors();
8380
},

src/index.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
module.exports = require("./formGenerator.vue");
2-
1+
module.exports = {
2+
component: require("./formGenerator.vue"),
3+
schema: require("./utils/schema.js"),
4+
validators: require("./utils/validators.js")
5+
};

src/utils/schema.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {get, set, each, isString, isArray, isFunction} from 'lodash';
2+
3+
module.exports.createDefaultObject = function (schema, obj = {}){
4+
each(schema.fields, (field) => {
5+
if (get(obj, field.model) === undefined)
6+
set(obj, field.model, field.default)
7+
});
8+
return obj;
9+
}
10+
11+
module.exports.getMultipleFields = function(schema) {
12+
let res = [];
13+
each(schema.fields, (field) => {
14+
if (field.multi === true)
15+
res.push(field);
16+
});
17+
18+
return res;
19+
}
20+
21+
module.exports.mergeMultiObjectFields = function(schema, objs) {
22+
let model = {};
23+
24+
let fields = module.exports.getMultipleFields(schema);
25+
26+
each(fields, (field) => {
27+
let mergedValue = undefined;
28+
let notSet = true;
29+
let path = field.model;
30+
31+
each(objs, (obj) => {
32+
let v = get(obj, path);
33+
if (notSet) {
34+
mergedValue = v;
35+
notSet = false;
36+
}
37+
else if (mergedValue != v) {
38+
mergedValue = undefined;
39+
}
40+
});
41+
42+
set(model, path, mergedValue);
43+
});
44+
45+
return model;
46+
}

src/utils/validators.js

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { isNil, isNumber, isString } from 'lodash';
2+
import moment from "moment";
3+
4+
function checkEmpty(value, required) {
5+
if (isNil(value) || value === "") {
6+
if (required)
7+
return ["This field is required!"];
8+
else
9+
return [];
10+
}
11+
return null;
12+
}
13+
14+
module.exports = {
15+
16+
number(value, field) {
17+
let res = checkEmpty(value, field.required); if (res != null) return res;
18+
19+
let err = [];
20+
if (isNumber(value)) {
21+
if (!isNil(field.min) && value < field.min)
22+
err.push("The number is too small! Minimum: " + field.min);
23+
24+
if (!isNil(field.max) && value > field.max)
25+
err.push("The number is too big! Maximum: " + field.max);
26+
27+
} else
28+
err.push("This is not a number!");
29+
30+
return err;
31+
},
32+
33+
integer(value, field) {
34+
let res = checkEmpty(value, field.required); if (res != null) return res;
35+
36+
if (!(Number(value) === value && value % 1 === 0))
37+
return ["Invalid number!"]
38+
},
39+
40+
double(value, field) {
41+
let res = checkEmpty(value, field.required); if (res != null) return res;
42+
43+
if (!(Number(value) === value && value % 1 !== 0))
44+
return ["Invalid number!"]
45+
},
46+
47+
string(value, field) {
48+
let res = checkEmpty(value, field.required); if (res != null) return res;
49+
50+
let err = [];
51+
if (isString(value)) {
52+
if (!isNil(field.min) && value.length < field.min)
53+
err.push(`The length of text is too small! Current: ${value.length}, Minimum: ${field.min}`);
54+
55+
if (!isNil(field.max) && value.length > field.max)
56+
err.push(`The length of text is too big! Current: ${value.length}, Maximum: ${field.max}`);
57+
58+
} else
59+
err.push("This is not a text!");
60+
61+
return err;
62+
},
63+
64+
date(value, field) {
65+
let res = checkEmpty(value, field.required); if (res != null) return res;
66+
67+
let m = moment(value);
68+
if (!m.isValid())
69+
return ["Invalid date!"];
70+
71+
let err = [];
72+
73+
if (!isNil(field.min)) {
74+
let min = moment(field.min);
75+
if (m.isBefore(min))
76+
err.push(`The date is too early! Current: ${m.format("L")}, Minimum: ${min.format("L")}`);
77+
}
78+
79+
if (!isNil(field.max)) {
80+
let max = moment(field.max);
81+
if (m.isAfter(max))
82+
err.push(`The date is too late! Current: ${m.format("L")}, Maximum: ${max.format("L")}`);
83+
}
84+
85+
return err;
86+
},
87+
88+
regexp(value, field) {
89+
let res = checkEmpty(value, field.required); if (res != null) return res;
90+
91+
if (!isNil(field.pattern)) {
92+
let re = new RegExp(field.pattern);
93+
if (!re.test(value))
94+
return ["Invalid format!"];
95+
}
96+
},
97+
98+
email(value, field) {
99+
let res = checkEmpty(value, field.required); if (res != null) return res;
100+
101+
let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
102+
if (!re.test(value))
103+
return ["Invalid e-mail address!"];
104+
},
105+
106+
url(value, field) {
107+
let res = checkEmpty(value, field.required); if (res != null) return res;
108+
109+
let re = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g
110+
if (!re.test(value))
111+
return ["Invalid URL!"];
112+
},
113+
114+
creditCard(value, field) {
115+
let res = checkEmpty(value, field.required); if (res != null) return res;
116+
117+
/* From validator.js code
118+
https://github.com/chriso/validator.js/blob/master/src/lib/isCreditCard.js
119+
*/
120+
const creditCard = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/;
121+
const sanitized = value.replace(/[^0-9]+/g, '');
122+
if (!creditCard.test(sanitized)) {
123+
return ["Invalid card format!"];
124+
}
125+
let sum = 0;
126+
let digit;
127+
let tmpNum;
128+
let shouldDouble;
129+
for (let i = sanitized.length - 1; i >= 0; i--) {
130+
digit = sanitized.substring(i, (i + 1));
131+
tmpNum = parseInt(digit, 10);
132+
if (shouldDouble) {
133+
tmpNum *= 2;
134+
if (tmpNum >= 10) {
135+
sum += ((tmpNum % 10) + 1);
136+
} else {
137+
sum += tmpNum;
138+
}
139+
} else {
140+
sum += tmpNum;
141+
}
142+
shouldDouble = !shouldDouble;
143+
}
144+
145+
if (!((sum % 10) === 0 ? sanitized : false))
146+
return ["Invalid card number!"];
147+
},
148+
149+
alpha(value, field) {
150+
let res = checkEmpty(value, field.required); if (res != null) return res;
151+
152+
// TODO
153+
},
154+
155+
alphaNumeric(value, field) {
156+
let res = checkEmpty(value, field.required); if (res != null) return res;
157+
158+
// TODO
159+
}
160+
}

0 commit comments

Comments
 (0)