Closed backnext321 closed 1 year ago
in the json you submit to json form there are three sections
schema:{} form:[] value:{}
see https://github.com/jsonform/jsonform/wiki#previous
so you put the previous data in the value section , no code changes required
from one of my uses, not the complete jsonform document, but a section from each for a data element (config)
{
"schema": {
"config": {
"type": "object",
"title": "properties for MagicMirror base",
"properties": {
"address": {
"type": "string",
"title": "address",
"enum": [
"localhost",
"0.0.0.0",
"192.168.2.106",
"172.17.0.1",
"169.254.86.97",
"192.168.152.1",
"172.16.141.1"
]
},
"port": {
"type": "number",
"title": "port"
},
"basePath": {
"type": "string",
"title": "basePath"
},
"language": {
"type": "string",
"title": "language",
"enum": [
"af",
"bg",
"ca",
"cs",
"cv",
"cy",
"da",
"de",
"el",
"en",
"es",
"et",
"fi",
"fr",
"fy",
"gl",
"gu",
"he",
"hi",
"hr",
"hu",
"id",
"is",
"it",
"ja",
"ko",
"lt",
"ms-my",
"nb",
"nl",
"nn",
"pl",
"ps",
"pt-br",
"pt",
"ro",
"ru",
"sk",
"sv",
"tlh",
"tr",
"translations",
"uk",
"zh-cn",
"zh-tw"
]
},
"locale": {
"type": "string",
"title": "locale"
},
"logLevel": {
"type": "array",
"title": "logLevel",
"items": {
"type": "string",
"enum": [
"INFO",
"LOG",
"WARN",
"ERROR",
"DEBUG"
]
}
},
"timeFormat": {
"type": "number",
"title": "timeFormat",
"enum": [
12,
24
]
},
"units": {
"type": "string",
"title": "units",
"enum": [
"imperial",
"metric"
]
},
"useHttps": {
"type": "boolean",
"title": "useHttps"
},
"ipWhitelist": {
"type": "array",
"title": "ipWhitelist",
"items": {
"type": "string"
}
}
}
},
},
"form":[
....
"type": "fieldset",
"title": "Base",
"expandable": true,
"items": [
{
"key": "config.address",
"titleMap": {
"localhost": "localhost - application access only from same machine",
"0.0.0.0": "0.0.0.0 - application access from any machine that can access network",
"192.168.2.106": "192.168.2.106 - application access only from machine on same network",
"172.17.0.1": "172.17.0.1 - application access only from machine on same network",
"169.254.86.97": "169.254.86.97 - application access only from machine on same network",
"192.168.152.1": "192.168.152.1 - application access only from machine on same network",
"172.16.141.1": "172.16.141.1 - application access only from machine on same network"
}
},
"config.port",
"config.basePath",
"config.language",
"config.locale",
{
"key": "config.logLevel",
"type": "checkboxes"
},
"config.timeFormat",
"config.units",
"config.useHttps",
{
"type": "array",
"deleteCurrent": false,
"title": "ipWhitelist",
"items": [
{
"key": "config.ipWhitelist[]",
"title": "ipWhitelist {{idx}}"
}
]
}
]
},
],
"value":{
"config": {
"address": "0.0.0.0",
"port": 8090,
"basePath": "/",
"language": "en",
"locale": "en-IN",
"logLevel": [
"INFO",
"LOG",
"WARN",
"ERROR"
],
"timeFormat": 24,
"units": "metric",
"useHttps": false,
"ipWhitelist": []
}
}
}
My problem is I have javascript code inside json "form". So the "schema", "form" and "value" stays in the html file like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Form</title>
<link rel="stylesheet" type="text/css" href="deps/opt/bootstrap.css" />
</head>
<body>
<div class="container">
<h2>Form</h2>
<div><img id="x" src="fotos/kleintjes/geenAfbeelding.jpg"></div>
<form></form>
</div>
<div id="res" class="alert"></div>
<script type="text/javascript" src="deps/jquery.min.js"></script>
<script type="text/javascript" src="deps/underscore.js"></script>
<script type="text/javascript" src="deps/opt/jsv.js"></script>
<script type="text/javascript" src="lib/jsonform.js"></script>
<!--<script type="text/javascript" src="deps/opt/jquery-ui.js"></script>--><!--dit toevoegen om zinnen van plaats te wisselen-->
<script type="text/javascript">
var x = 0;
var lengte = 0;
var resultArray = [];
const editedText = "";
var value = "";
var previouslySubmitted = ({ "fotos": [{ "foto": ["foto1"], "tekst": ["text1"] }, { "foto": ["foto2"], "tekst": ["text2"] }] }); $('form').jsonForm({
schema: {
fotos: {
type: 'array',
maxItems: 4,
items: {
type: 'object',
title: 'Foto',
properties: {
foto: {
type: 'string',
description: 'Bestandsnaam van de foto zonder extensie. (.jpg)',
title: "Foto nr {{idx}}",
maxItems: 1,
},
tekst: {
type: 'array',
maxItems: 3,
items: {
type: 'string',
title: 'tekst'
}
}
}
}
}
},
form: [
{
type: 'tabarray',
items: {
type: 'section',
title: '{{idx}}',
items: [
'fotos[].foto',
{
type: 'array',
items: [
'fotos[].tekst[]'
]
},
]
},
onClick: function (evt) {
var value = $(evt.target).val();
document.getElementById("x").src = 'fotos/kleintjes/' + value + '.jpg';
var fotonaam = 'fotos/kleintjes/' + value + '.jpg';
checkImage(fotonaam,
function () {
// exists
},
function () {
document.getElementById('x').src = 'fotos/kleintjes/geenAfbeelding.jpg';
});
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
};
}
},
{
type: 'submit',
title: 'Verstuur'
}
],
value: {
fotos: [
{ "foto": ["FirstFoto"], "tekst": ["First Text"] }
]
},
onSubmit: function (errors, values) {
if (errors) {
$('#res').html('<p>Wrong?</p>');
} else {
const JSONbasis = values.fotos;
lengte = JSONbasis.length;
for (let i = 0; i < lengte; i++) {
const propertyValues = Object.values(values.fotos[i]);//values
const jsonStringpropertyValues1 = ('{"foto":' + JSON.stringify(propertyValues[0]));// foto
const jsonStringpropertyValues2 = JSON.stringify(Object.assign({}, propertyValues[1]));// tekst
const result = jsonStringpropertyValues1.concat(jsonStringpropertyValues2);
const resultB = result.replace('"{"', '","');
const resultC = resultB.replaceAll('","', '","zz');
resultArray.push([resultC]);
}
console.log("resultArray= " + resultArray);
console.log("JSON.stringify(values) = " + JSON.stringify(values));
}
}
});
</script>
</body>
</html>
and? just make your jsonform a variable (as it is an unnamed one now) and then change the value section
const formvar= {
schema: {
fotos: {
type: 'array',
maxItems: 4,
items: {
type: 'object',
title: 'Foto',
properties: {
foto: {
type: 'string',
description: 'Bestandsnaam van de foto zonder extensie. (.jpg)',
title: "Foto nr {{idx}}",
maxItems: 1,
},
tekst: {
type: 'array',
maxItems: 3,
items: {
type: 'string',
title: 'tekst'
}
}
}
}
}
},
form: [
{
type: 'tabarray',
items: {
type: 'section',
title: '{{idx}}',
items: [
'fotos[].foto',
{
type: 'array',
items: [
'fotos[].tekst[]'
]
},
]
},
onClick: function (evt) {
var value = $(evt.target).val();
document.getElementById("x").src = 'fotos/kleintjes/' + value + '.jpg';
var fotonaam = 'fotos/kleintjes/' + value + '.jpg';
checkImage(fotonaam,
function () {
// exists
},
function () {
document.getElementById('x').src = 'fotos/kleintjes/geenAfbeelding.jpg';
});
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
};
}
},
{
type: 'submit',
title: 'Verstuur'
}
],
value: {
fotos: [
{ "foto": ["FirstFoto"], "tekst": ["First Text"] }
]
},
onSubmit: function (errors, values) {
if (errors) {
$('#res').html('<p>Wrong?</p>');
} else {
const JSONbasis = values.fotos;
lengte = JSONbasis.length;
for (let i = 0; i < lengte; i++) {
const propertyValues = Object.values(values.fotos[i]);//values
const jsonStringpropertyValues1 = ('{"foto":' + JSON.stringify(propertyValues[0]));// foto
const jsonStringpropertyValues2 = JSON.stringify(Object.assign({}, propertyValues[1]));// tekst
const result = jsonStringpropertyValues1.concat(jsonStringpropertyValues2);
const resultB = result.replace('"{"', '","');
const resultC = resultB.replaceAll('","', '","zz');
resultArray.push([resultC]);
}
console.log("resultArray= " + resultArray);
console.log("JSON.stringify(values) = " + JSON.stringify(values));
}
}
};
formvar.value=previouslySubmitted //(take off the parens, not needed)
$(form).jsonForm(formvar) // generate the form
then if u need to adjust the form, fix it and regen to the same div.
I send my jsonform document to my web client over socket.io, make some corrections, and then generate it. I do like this
// receive the form text from host
activesocket.on("json", function (incoming_json) {
// convert to object
let data = parseData(incoming_json.slice(1, -1));
// free the memory
incoming_json = null;
// save pointers to data sent with the form object
let pairs = data.pairs;
let arrays = data.arrays;
let objects = data.objects;
let mangled_names = data.mangled_names;
let convertedObjects = data.convertedObjects;
// clear any text left over in the output error field
$("#outmessage").text("");
// add the submit handlers to the jsonform object
// submitValid
data.onSubmitValid = function (values) {
// restore the fixup data from the incoming
values["pairs"] = pairs;
values["arrays"] = arrays;
values["objects"] = objects;
values["mangled_names"] = mangled_names;
values["convertedObjects"] = convertedObjects;
activesocket.emit("saveConfig", values);
$("#outmessage").html(
"<p><strong>Your Configuration has been submitted.</strong></p>"
);
};
// submit
data.onSubmit = function (errors, values) {
if (errors) {
console.log("Validation errors 1", errors, values);
let buildInner = "";
errors.forEach(function (errItem) {
let errSchemaUri = errItem.schemaUri
.replace(/.+\/properties\//, "")
.replace("/", " >> ");
buildInner +=
`<p><strong style="font-color:red">Error: ` +
errItem.message +
"</strong></br>Location: " +
errSchemaUri +
"</p>";
});
$("#outMsg").html(buildInner);
console.log("Validation errors 2", values);
return false;
}
return true;
};
// replace any form from last connection
$("#result").html('<form id="result-form" class="form-vertical"></form>');
// generate the new form to the element id (using the id of the element injected in prior statement)
$("#result-form").jsonForm(data);
Thanx. This helps me a lot. Just one more thing: I would like to put an image at the top of the form that corresponds to the first item of the tabarray. I try something like this:
onClick: function (evt) {
var value = $(evt.target).val();
var fotonaam = 'fotos/kleintjes/' + value + '.jpg';
checkImage(fotonaam,
function () {
//exists
document.getElementById('x').src = fotonaam;
},
function () {
// not
});
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
};
}
But now one has to click the inputfield each time. This is not a good solution. Any idea?
what do you mean first? when the form is generated? or when the tab is selected?
if when form is generated, you know what the 1st tab will be, so you can inject that info to another element in the html above the form element.
if when the tab is selected you can add an on change handler to the tabarray. you are clicking that already
Thank you for viewing this. I'm almost there but not quite. When form is generated, the image is showing up. When the tab is selected I have still a strange problem: If I use onChange nothing happens when I click on the tab. If I use onClick -as in the example here- it works but I have to click twice on the tab every time before the image shows up. Searched for hours but no solution found.
<head>
<meta charset="utf-8" />
<title>Form</title>
<link rel="stylesheet" type="text/css" href="deps/opt/bootstrap.css" />
</head>
<body>
<div class="container">
<h2>Form</h2>
<div><img id="x" src="fotos/kleintjes/geenAfbeelding.jpg"></div>
<form></form>
<p id="demo"></p>
</div>
<div id="res" class="alert"></div>
<script type="text/javascript" src="deps/jquery.min.js"></script>
<script type="text/javascript" src="deps/underscore.js"></script>
<script type="text/javascript" src="deps/opt/jsv.js"></script>
<script type="text/javascript" src="lib/jsonform.js"></script>
<!--<script type="text/javascript" src="deps/opt/jquery-ui.js"></script>--><!--dit toevoegen om zinnen van plaats te wisselen-->
<script type="text/javascript">
function tekstOpmaak(antwoord) {
var x = 0;
var lengte = 0;
var resultArray = [];
const formvar = {
schema: {
fotos: {
type: 'array',
maxItems: 4,
items: {
type: 'object',
title: 'Foto',
properties: {
foto: {
type: 'string',
title: 'Bestandsnaam van de foto zonder ".jpg"',
maxItems: 1,
required: true
},
tekst: {
type: 'array',
maxItems: 3,
items: {
type: 'string',
title: 'tekst'
}
}
}
}
}
},
form: [
{
key: "fotos",
type: 'tabarray',
onClick: function () {
let elements = document.getElementsByClassName('active');
let data = [].map.call(elements, elem => elem.textContent);
let data_0 = data[0] - 1;
console.log("data_0 = " + data_0);
let fotoData_0 = JSON.stringify(antwoord.fotos[data_0].foto[0]);
var fotoData_0_Sliced = fotoData_0.slice(1, -1);
console.log("fotoData_0_Sliced = " + fotoData_0_Sliced);
var fotonaam = 'fotos/kleintjes/' + fotoData_0_Sliced + '.jpg';
checkImage(fotonaam,
function () {
//exists
document.getElementById('x').src = fotonaam;
},
function () {
// exists not
document.getElementById('x').src = 'fotos/kleintjes/geenAfbeelding.jpg';
});
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
};
},
items: {
type: 'section',
title: '{{idx}}',
items: [
'fotos[].foto',
{
type: 'array',
notitle: true,
items: [
'fotos[].tekst[]'
]
},
]
},
},
{
type: 'submit',
title: 'Verstuur'
}
],
onSubmit: function (errors, values) {
if (errors) {
$('#res').html('<p>Is er iets fout gegaan?</p>');
} else {
const JSONbasis = values.fotos;
lengte = JSONbasis.length;
for (let i = 0; i < lengte; i++) {
const propertyValues = Object.values(values.fotos[i]);//values
const jsonStringpropertyValues1 = ('{"foto":' + JSON.stringify(propertyValues[0]));// foto
const jsonStringpropertyValues2 = JSON.stringify(Object.assign({}, propertyValues[1]));// tekst
const result = jsonStringpropertyValues1.concat(jsonStringpropertyValues2);
const resultB = result.replace('"{"', '","');
const resultC = resultB.replaceAll('","', '","zz');
resultArray.push([resultC]);
}
}
}
};
formvar.value = antwoord;
var showFoto = JSON.stringify(formvar.value.fotos[0].foto[0]);// voorlaatste [0] vervangen door variabele...
var showFoto = showFoto.slice(1, -1);
console.log('showFoto = ' + showFoto);
console.log('showFoto = ' + showFoto);
document.getElementById("x").src = 'fotos/kleintjes/' + showFoto + '.jpg';
$('form').jsonForm(formvar); // generate the form
}
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
//if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//}
var myObj = JSON.parse(this.responseText);
tekstOpmaak(myObj);
}
xmlhttp.open("GET", "hoofdstukken/JSONformtest2.txt");
xmlhttp.send();
</script>
</body>
click fires BEFORE the tag focus change change fires AFTER ( I believe)
you can debug this in the browser developers console, ctrl-shift-i, select the sources tab.. (chrome, firefox and edge) find your web page code in the left nav/
I think I found a solution. The function where I get the value of the 'tabarray' with "document.getElementsByClassName('active');" should be slightly delayed with 'setTimeout'. In this function I ask for the 'value' of the input field of the photo as below:
let elements = document.getElementsByClassName('active');
let data = [].map.call(elements, elem => elem.textContent);
let data_0 = data[0] - 1;
let data_0_Id = 'jsonform-1-elt-fotos[' + data_0 + '].foto';
var inputfield = document.getElementById(data_0_Id).value;
console.log("inputfield = " + inputfield);
var fotonaam = 'fotos/kleintjes/' + inputfield + '.jpg';
cool!. all this is not really a jsonform issue, but app design. I have two independent sections in my firm, but they have to stay in sync. JavaScript functions are the only way!
Uhm. One more little question: How can I place the glyphicon-minus-sign of an array at the left of the input field instead of under this field? This to save space if there are more input fields in the form.
sorry got a pic of that? you mean the +/- add remove buttons? currently no way to move them
I mean the remove button under the input field. When in Chrome Devtools I put
Here the screenshot form2.jpg I meant.
yes see #417 that asks the same.. no way to do that currently
I see. Now I have a form a bit like 'Navigation Tabs' in the playground. I need to change the "enum" values from outside the Json. I have some code for this but the onsubmit doesn't work anymore. Any suggestion?
sorry, unclear what you mean ..
maybe you have the jsonform js object again
{
"schema": {
"favorite_movie":{
"type":"string",
"title":"Favorite Movie",
"enum":[
"Field of Dreams",
"Braveheart",
"A League of Their Own"
]
},
then
object.schema.favorite_movie.enum=[...... new list ]
or
object.schema['favorite_movie'].enum = [ ..... new list ]
then regenerate the form.. you cannot change them WHILE the form is being executed... submit, change, regen...
I don't get it. I've done this so far. When I stringifyand then parse the formvar, the onsubmit part is no longer there...
`<!DOCTYPE html>
correct, the sumbitted form only has data in it, not any of the form construct
if u add the on submits to the form after gen vs part of the form json.
then u have to add it again after form gen
I begin to understand the logic of these forms. It works this way. Thank you for quick help.
In #417 you mentioned "in #419 I added a form setting to allow removing the delete current item button..": "deleteCurrent: false," But where should I place "deleteCurrent: false". I tried in the form but nothing changes...
in the form section, for the array element.
last year I needed to disable the drag, so I added draggable:false
this deleteCurrent is only in that PR, not in the current released code
In jsonform.js after:
var $nodeid = $(node.el).find('#' + escapeSelector(node.id));
I added:
$nodeid.find('a._jsonform-array-deletecurrent').addClass('hide');
also after places where 'a._jsonform-array-deletecurrent'.
Now "deletecurrent" is hidden.
@backnext321 just be careful updating the code, if u take any updates...
can we close this?
Yes, thank you for helping me and best wishes.
First of all: thank you for sharing this beautiful system. I'm looking for a way to change the 'previously submitted values'. I want to download an 'array' from the server and put it in the 'previously submitted values' first. The only way I've found so far is to replace in jsonform.js:
with
Where previouslySubmitted is a variable ( in my html) from server:
var previouslySubmitted = ({"fotos":[{"foto":["foto1"],"tekst":["text1"]},{"foto":["foto2"],"tekst":["text2"]}]});
But I'm sure there is an easier way to achieve this. Any suggestion?