dynamic recusive form

This commit is contained in:
Sebastian Frank 2017-12-13 14:24:59 +01:00
parent f49153603a
commit bf6dc2c944
No known key found for this signature in database
GPG Key ID: DC2BC5C506EBF6F3
6 changed files with 189 additions and 33 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

18
package-lock.json generated
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",

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);
}
*/
}
}
}

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);
}
}

View File

@ -28,8 +28,10 @@ export default {
key: "username",
element: "my-input",
icon: "icon-user",
required: true,
requiredMessage: "Der Benutzername wird benötigt!",
validate: {
required: true,
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",
required: true,
requiredMessage: "Das Passwort wird benötigt!",
validate: {
required: true,
requiredMessage: "Das Passwort wird benötigt!"
},
props: {
type: "password",
placeholder: "Passwort"