dynamic recusive form

This commit is contained in:
Sebastian Frank
2017-12-13 14:24:59 +01:00
parent f49153603a
commit bf6dc2c944
6 changed files with 189 additions and 33 deletions
+3 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -9
View File
@@ -6902,15 +6902,6 @@
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
"dev": true
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@@ -6944,6 +6935,15 @@
}
}
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+115 -9
View File
@@ -1,3 +1,4 @@
<!--
<template>
<form @submit.prevent="submit()">
<div v-for="(el, idx) in elements" :key="idx">
@@ -19,10 +20,77 @@
</div>
</form>
</template>
-->
<script>
import MyInput from 'components/my-input.vue';
export default {
name: "MyForm",
render(createElement) {
let self = this;
let _cElCall;
_cElCall = function(elements, formData) {
let formEl = [ ];
elements.forEach(el => {
let n = el.name ? el.name : el.key;
switch (el.element) {
case "my-input":
formEl.push(createElement(MyInput, {
props: {
name: n,
label: el.label,
description: el.description,
props: el.props,
value: formData[n],
validate: el.validate
},
on: {
input(val) {
formData[n] = val;
},
validate(valid) {
el.valid = valid;
}
}
}));
break;
case "section":
formEl.push(createElement("h3", el.label));
if (!formData[n]) {
formData[n] = { };
}
formEl.push(createElement("div", _cElCall(el.subElements, formData[n])));
break;
}
});
return formEl;
}
let formElements = _cElCall(this.elements, self.formData);
this.buttons.forEach(b => {
formElements.push(createElement("button", {
class: {
button: true
},
on: {
click(event) {
event.preventDefault();
self.buttonClick(b.type);
}
}
}, b.label ? b.label : "OK"))
})
return createElement('form', {
on: {
submit(e) {
e.preventDefault();
}
}
}, formElements)
},
props: {
initData: {
type: Object,
@@ -52,29 +120,29 @@ export default {
data() {
return {
formData: this.initData,
formErrors: {},
elementsMap: {}
// formErrors: {},
// elementsMap: {}
}
},
created() {
/*created() {
this.setOrder();
},
},*/
watch: {
elements() {
/*elements() {
this.setOrder();
},
},*/
initData() {
this.formData = this.initData;
}
},
methods: {
setOrder() {
/*setOrder() {
this.elementsMap = {};
for (let a in this.elements) {
this.elementsMap[this.elements[a].key] = this.elements[a];
}
},
validateData(name) {
},*/
/*validateData(name) {
if (this.elementsMap[name].required) {
if (!this.formData[name]) {
this.$set(this.formErrors, name, {
@@ -88,6 +156,17 @@ export default {
}
return true;
},
validateElement(el, val) {
if (el.validate) {
let v = el.validate;
if (v.required && !val) {
el.validatorMessage = v.requiredMessage ? v.requiredMessage : "input is required";
return false;
}
}
return true;
},*/
buttonClick(type) {
switch(type) {
case 'submit':
@@ -96,6 +175,32 @@ export default {
}
},
submit() {
// bad hacky solution, but works
this.$children.forEach(c => {
c.validateValue();
});
let _validateE;
_validateE = function(eArr) {
for (let i = 0; i< eArr.length; ++i) {
if (eArr[i].valid === false) {
return false;
} else if (eArr[i].subElements) {
// validate subElements
let subValid = _validateE(eArr[i].subElements);
if (!subValid) {
return false;
}
}
}
return true;
}
if (_validateE(this.elements)) {
this.submitHandler(this.formData);
}
/*
let valid = true;
Object.keys(this.elementsMap).forEach(key => {
valid = (this.validateData(key) && valid);
@@ -103,6 +208,7 @@ export default {
if (valid) {
this.submitHandler(this.formData);
}
*/
}
}
}
+53 -7
View File
@@ -6,13 +6,22 @@
</div>
<!-- -->
<input type="number" v-if="props && props.type == 'number'"
v-model="currentValue"
:class="{invalid}"
:id="name"
:name="name"
:placeholder="props.placeholder"
@blur="validateValue"
@change="handleChange"
>
<input type="text" v-if="props && props.type == 'text'"
v-model="currentValue"
:class="{invalid}"
:id="name"
:name="name"
:placeholder="props.placeholder"
@blur="validate"
@blur="validateValue"
@change="handleChange"
>
<input type="password" v-else-if="props && props.type == 'password'"
@@ -21,7 +30,7 @@
:id="name"
:name="name"
:placeholder="props.placeholder"
@blur="validate"
@blur="validateValue"
@change="handleChange"
>
<div class="checkbox_holder" v-else-if="props && props.type == 'checkbox'">
@@ -30,6 +39,7 @@
v-model="currentValue"
:id="name"
:name="name"
@blur="validateValue"
@change="handleChange"
>
<div class="check_checkbox"></div>
@@ -54,17 +64,29 @@ export default {
'name',
'props',
'value',
'invalid',
'validatorMessage'
// 'invalid',
// 'validatorMessage',
'validate'
],
data() {
return {
currentValue: this.value
currentValue: this.value,
invalid: false,
validatorMessage: ""
}
},
methods: {
validate() {
this.$emit('validate', this.currentValue);
validateValue() {
var valid = true;
let v = this.validate;
if (v) {
if (v.required && !this.currentValue) {
valid = false;
this.validatorMessage = (typeof v.requiredMessage == "string") ? v.requiredMessage : "input required";
}
}
this.invalid = !valid;
this.$emit('validate', valid);
},
handleChange() {
this.$emit('change', this.currentValue);
@@ -72,6 +94,30 @@ export default {
},
watch: {
currentValue(val) {
if (this.props && this.props.datatype) {
// convert
let t = this.props.datatype;
let newVal;
switch (t) {
case "int":
newVal = parseInt(this.currentValue);
if (isNaN(newVal)) {
newVal = 0;
}
break;
case "float":
newVal = parseFloat(this.currentValue);
if (isNaN(newVal)) {
newVal = 0;
}
break;
}
if (newVal !== this.currentValue) {
this.currentValue = newVal;
return; // prevent double input events
}
}
this.$emit('input', val);
}
}
+6 -2
View File
@@ -28,8 +28,10 @@ export default {
key: "username",
element: "my-input",
icon: "icon-user",
validate: {
required: true,
requiredMessage: "Der Benutzername wird benötigt!",
requiredMessage: "Der Benutzername wird benötigt!"
},
props: {
type: "text",
placeholder: "Benutzername"
@@ -39,8 +41,10 @@ export default {
key: "password",
element: "my-input",
icon: "icon-key",
validate: {
required: true,
requiredMessage: "Das Passwort wird benötigt!",
requiredMessage: "Das Passwort wird benötigt!"
},
props: {
type: "password",
placeholder: "Passwort"