Get cascading data from form into JSON object - javascript

I am trying to build a 'form builder' where you can add sub-fields to fields, and sub-fields to those sub-fields, etc. I have that part working and the output html I have pasted here on pastebin
Which looks like:
I need to get the data into this format:
var form_structure = {
iGA2cXN3XXdmr1F: {
title: "Field 1",
help: "",
placeholder: "",
type: "multi-select",
options: {"123QWE": "Opt 1", "ASDZXC": "Opt 2", "ASDQWE": "Opt 3"},
subfields: {
m8r32skADKsQwNt: {
title: "Field 1.1",
help: "",
placeholder: "",
type: "text",
options: []
},
m8r32skADKsQwNt: {
title: "Field 1.2",
help: "",
placeholder: "",
type: "text",
options: []
},
m8r32skADKsQwNt: {
title: "Field 1.3",
help: "",
placeholder: "",
type: "text",
options: [],
subfields: {
m8r32skADKsQwNt: {
title: "Field 1.3.1",
help: "",
placeholder: "",
type: "text",
options: []
}
}
}
}
},
aBvXXN3XXdmr1F: {
title: "Field 2",
help: "",
placeholder: "",
type: "multi-select",
options: {"123QWE": "Opt 1", "ASDZXC": "Opt 2", "ASDQWE": "Opt 3"},
subfields: {
m8r32skADKsQwNt: {
title: "Field 2.1",
help: "",
placeholder: "",
type: "text",
options: []
}
}
}
};
I have tried (sorry for the bad formatting):
function buildRequestStringData(form) {
var select = form.find('select'),
input = form.find('input'),
options_arr = [],
obj = {},
requestString = '{';
for (var i = 0; i < select.length; i++) {
if(typeof $(select[i]).data('parentid') != 'undefined') {
// has parent
if($(select[i]).data('parentid') != $(select[i]).data('mainid')) {
requestString += '"' + $(input[i]).data('mainid') + '":"' + JSON.stringify(buildRequestStringData()) + '",';
}
} else {
// does not have parent
requestString += '"' + $(select[i]).attr('name') + '": "' +$(select[i]).val() + '",';
}
}
// if (select.length > 0) {
// requestString = requestString.substring(0, requestString.length - 1);
// }
for (var i = 0; i < input.length; i++) {
// if ($(input[i]).attr('type') !== 'checkbox') {
requestString += '"' + $(input[i]).attr('name') + '":"' + $(input[i]).val() + '",';
// } else {
// if ($(input[i]).attr('checked')) {
// requestString += '"' + $(input[i]).attr('name') +'":"' + $(input[i]).val() +'",';
// }
// }
}
if (input.length > 0) {
requestString = requestString.substring(0, requestString.length - 1);
}
requestString += '}]';
return requestString;
}
The best way I have been able to be close to this is on this fiddle - but that only allows me to put the id down, and does not format it into the format I need.
What is the best way to do this?

I think you're on the right track. See if you can nest your HTML in the same structure you want for your JSON, then when harvesting the details for each item, walk up the DOM tree grabbing each parent's id until you get to the form, and then create / append to the nested JSON object the data you find. If this isn't descriptive enough, I'll mod the answer to include html and js examples.

Related

Parse JSON dynamically and print key values on html with input checkbox and get a new JSON of selected keys

I am trying to parse an unknown JSON whose format could be anything. So, I dont know the keys to access it. I want to access every key in JSON and print out all keys and values on screen using HTML. So I made a recursive function to access every key in JSON and used a variable name html to print the keys.
here`s the code:
JSON String:
{
"FetchDetails": {
"TransactionDetails": {
"ServiceName": "Airtel Mobile Bill Postpaid",
"officeID": "209",
"BillAmount": "931.00",
"ConsumerName": "Chetan Kumar Yadav",
"consumerKeysValues": "9352423664",
"partPaymentAllow": "1",
"partPaymentType": "Both",
"lookUpId": "6163298",
"officeCodeValue": "RATNC011"
},
"BillDetails": [{
"LableName": "Amount Before Due Date",
"LableValue": "931.00"
}, {
"LableName": "Due Date",
"LableValue": "NA"
}, {
"LableName": "Mobile Number",
"LableValue": "9352423664"
}, {
"LableName": "Amount After Due Date",
"LableValue": "931.00"
}, {
"LableName": "Bill Date",
"LableValue": "NA"
}, {
"LableName": "Consumer Name",
"LableValue": "Chetan Kumar Yadav"
}, {
"LableName": "Bill Cycle",
"LableValue": "NA"
}, {
"LableName": "Bill Number",
"LableValue": "NA"
}, {
"LableName": "Account Number",
"LableValue": "1116231291"
}]
}
}
Heres the code to access every key in Parsed JSON
function scan(info) {
var sub_root = [];
if (info instanceof Object) {
for (k in info) {
if (info.hasOwnProperty(k)) {
console.log('scanning property ' + k);
if (info[k] instanceof Object) {
me += "<div class='root'> <div class='sub_root'> <input class='node' name='sub_root[" + k + "]' value='" + k + "' type='checkbox' />" + k;
console.log(k);
counter++;
scan(info[k]);
me += "</div>";
me += "</div>";
} else {
me += "<div class='json_check' ><input class='node' name='sub_root[" + y + "] [" + k + "]' value='" + k + "' type='checkbox' />" + k + ": " + info[k] + " </div>";
scan(info[k]);
counter++;
}
}
}
} else {
console.log('found value : ' + info);
}
}
After this, I am able to access every key in JSON and printed every node in a nested form with checkboxes in front of them to select any node/key.
Here`s the screenshot:
[PROBLEM to be solved]
Now at the bottom, I have a submit button, when I click on it I want to form a JSON of checked values with their parent nodes. So like if I check a key with a value, I should get its parent keys along with it.
For example: I have selected ServiceName and officeID in TransactionDetails, and some array values in BillDetails, so I should get something like this
{
"FetchDetails": {
"TransactionDetails": {
"ServiceName": "Airtel Mobile Bill Postpaid",
"officeID": "209"
},
"BillDetails": [{
"LableName": "Amount Before Due Date",
"LableValue": "931.00"
}, {
"LableName": "Due Date",
"LableValue": "NA"
}, {
"LableName": "Account Number",
"LableValue": "1116231291"
}]
}
}
[EDITED]
To get this JSON format and traverse through HTML objects I am writing this code:
$('#btn_createservice').on('click', function() {
var solid = '{';
var input = $('input').is(':checked');
if(input){
input = $('input');
}
$('.node:checked').each(function(index) {
var parentEls = $(this).closest(input)
.map(function() {
solid += this.value;
return this.value;
})
.get()
.join( ", " );
console.log(parentEls);
});
solid += '}';
$( ".submit_json" ).html(solid);
});
You need to use .parents(), not .closest() so you get all the containing elements.
Then create containing properties with those names when necessary.
$("#btn_createservice").on("click", function() {
var svc_obj = {};
$(".node:checked").each(function() {
var cur_obj = svc_obj;
$(this).parents(".node").map(function () {
return this.value;
}).get().reverse().forEach(function(name) {
if (!cur_obj[name]) { // create property if it doesn't already exist
cur_obj[name] = {};
}
cur_obj = cur_obj[name]; // use this for next iteration;
});
var thisname = this.name.match(/\[([^[])+\]$/)[1]; // Get property name from name="sub_root[...]"
cur_obj[thisname] = this.value;
});
$(".submit_json").html(JSON.stringify(svc_obj));
})
You need to fix the HTML you're creating so that the checkboxes have value='" + info[k] "'.

Objects deep/nested child-level comparison

I have two objects, I want to list changes between both as described below:
Currently I'm getting following output
current value || new value
title : Object 1 || title : Object 1 UPDATED
description : Object 1 Description || description : Object 1 Description UPDATED
Currently my code works for root level comparison(as highlighted above). But I am looking for comparisons on deep/nested child-level differences.
My output should look something like below
current value || new value
title : Object 1 || title : Object 1 UPDATED
description : Object 1 Description || description : Object 1 Description UPDATED
releations.tools[0].title: my first tool || releations.tools[0].title: my first tool UPDATED
relations.tools[0].types[1].name : test2 || DELETED
relations.training[0].description: training Description || relations.training[0].description: training Description UPDATED
relations.training[0].trainingTypes[1].name : in-person || DELETED
My current code
function diffObjects(obj1, obj2) {
let res = [];
let objKeysArray = _.keys(obj2) || [];
if (!obj1 || !obj2) {
return res;
}
if (objKeysArray.length === 0) {
return res;
}
_(objKeysArray).forEach((key) => {
console.log(obj1[key], obj2[key]);
if (_.isArray(obj1[key]) && _.isArray(obj2[key])) {
} else if (_.isObject(obj1[key]) && _.isObject(obj2[key])) {
} else if (!_.isEqual(obj1[key], obj2[key])) {
let change1 = `${key} : ${obj1[key]}`;
let change2 = `${key} : ${obj2[key]}`;
res.push({
currentVal: change1,
newVal: change2
});
}
});
return _.flattenDeep(res);
}
I have created a fiddle for above code here:
JSFiddle Link : https://jsfiddle.net/vr0pgemj/
I have already referenced these posts:
Deep comparison of objects/arrays
Javascript Deep Comparison
But they only give me TRUE or FALSE results and not the differences I am looking for.
I made a working fork of your fiddle here with ECMAscript6 syntax.
Here is an embedded version as well:
(function() {
'use strict';
function diffObj(obj1, obj2, ref) {
var prefix = ref || '';
var res = [];
if (!_.isUndefined(obj1) && _.isUndefined(obj2)) {
res.push({
currentVal: prefix + ' : ' + JSON.stringify(obj1),
newVal: 'DELETED'
});
} else if (_.isUndefined(obj1) && !_.isUndefined(obj2)) {
res.push({
currentVal: 'DELETED',
newVal: prefix + ' : ' + JSON.stringify(obj2)
});
}
if (_.isUndefined(obj1) || _.isUndefined(obj2)) {
return _.flattenDeep(res);
}
var keys = _.uniq(_.keys(obj1).concat(_.keys(obj2)));
_(keys).forEach(function(key) {
var value1 = obj1[key];
var value2 = obj2[key];
if (!_.isUndefined(value1) && _.isUndefined(value2)) {
res.push({
currentVal: prefix + key + ' : ' + value1,
newVal: 'DELETED'
});
} else if (_.isUndefined(value1) && !_.isUndefined(value2)) {
res.push({
currentVal: 'DELETED',
newVal: prefix + key + ' : ' + value2
});
} else if (_.isArray(value1) && _.isArray(value2)) {
var entries = Math.max(value1.length, value2.length);
for (var i = 0; i < entries; i++) {
res.push(diffObj(value1[i], value2[i], prefix + key + '[' + i + '].'));
}
} else if (_.isObject(value1) && _.isObject(value2)) {
res.push(diffObj(value1, value2, prefix + key + '.'));
} else if (!_.isEqual(value1, value2)) {
res.push({
currentVal: prefix + key + ' : ' + value1,
newVal: prefix + key + ' : ' + value2
});
}
});
return _.flattenDeep(res);
}
var json1 = {
"id": 1,
"title": "Object 1",
"description": "Object 1 Description",
"test": "foo bar",
"relations": {
"tools": [{
"id": 2,
"title": "my first tool",
"description": "tools description",
"types": [{
"id": 123,
"name": "test"
}, {
"id": 111,
"name": "test2"
}]
}],
"training": [{
"id": 3,
"title": "Test training",
"description": "training Description",
"trainingTypes": [{
"id": 1,
"name": "online"
}, {
"id": 2,
"name": "in-person"
}, {
"id": 3,
"name": "boot camp"
}]
}]
}
};
var json2 = {
"id": 1,
"title": "Object 1 UPDATED",
"description": "Object 1 Description UPDATED",
"relations": {
"tools": [{
"id": 2,
"title": "my first tool UPDATED",
"description": "tools description",
"types": [{
"id": 123,
"name": "test"
}]
}],
"training": [{
"id": 3,
"title": "Test training",
"description": "training Description UPDATED",
"trainingTypes": [{
"id": 1,
"name": "online"
}, {
"id": 3,
"name": "boot camp"
}]
}]
}
};
var res = diffObj(json1, json2);
res = res.map(function(d) {
return '<tr><td>' + d.currentVal + '</td><td>' + d.newVal + '</td></tr>';
});
$('#tableResult > tbody').append(res);
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
<table id="tableResult" class="table table-hover table-striped">
<thead>
<tr>
<th>
current
</th>
<th>
new
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>

How to read array inside JSON Object this is inside another array

I am newbie to JSON, I am parsing a JSON Object and i was struck at a point where i have to read the array Elements inside a Object, that is again in another array..
Here is MY JSON
{
"DefinitionSource": "test",
"RelatedTopics": [
{
"Result": "",
"Icon": {
"URL": "https://duckduckgo.com/i/a5e4a93a.jpg"
},
"FirstURL": "xyz",
"Text": "sample."
},
{
"Result": "",
"Icon": {
"URL": "xyz"
},
"FirstURL": "xyz",
"Text": "sample."
},
{
"Topics": [
{
"Result": "",
"Icon": {
"URL": "https://duckduckgo.com/i/10d02dbf.jpg"
},
"FirstURL": "https://duckduckgo.com/Snake_Indians",
"Text": "sample"
},
{
"Result": "sample",
"Icon": {
"URL": "https://duckduckgo.com/i/1b0e4eb5.jpg"
},
"FirstURL": "www.google.com",
"Text": "xyz."
}
]
}
]
}
Here I need to read URL ,FIRSTURL and Text from RelatedTopics array and Topics array..
Can anyone help me. Thanks in advance.
Something like this
function (json) {
json.RelatedTopics.forEach(function (element) {
var url = element.Icon ? element.Icon.URL : 'no defined';
var firstURL = element.FirstURL ? element.FirstURL : 'no defined';
var text = element.Text ? element.Text : 'no defined';
alert("URL: " + url + "\nFirstURL: " + firstURL + "\nText: " + text);
if (element.Topics)
{
element.Topics.forEach(function (topicElement) {
alert("Topics - \n" + "URL: " + topicElement.Icon.URL + "\nFirstURL: " + topicElement.FirstURL + "\nText: " + topicElement.Text);
});
}
});
};
Look fiddle example
Loop through json Array like,
for(var i=0; i< RelatedTopics.length;i++){
if($.isArray(RelatedTopics[i])){
for(var j=0; j< RelatedTopics[i].Topics.length;j++){
var topics=RelatedTopics[i].Topics[j];
var text = topics.Text;
var firsturl = topics.Firsturl;
var url = topics.Icon.url;
}
}
}
if you want push it an array variable

Unable to display nested JSON on Sencha Touch 2

Consider this JSON
{
"stream": {
"posts": [{
"post_id": "1",
"post_type": "text",
"post_thumb": "bla1",
"comments": [{
"comment_id": "7",
"comment_text": "asd",
},
{
"comment_id": "8",
"comment_text": "sdf",
}],
}],
}
}
and my Model
Ext.define('MyAppApp.model.Post', {
extend: 'Ext.data.Model',
config: {
fields: [
'post_id',
'post_type',
'post_thumb',
'comments',
],
proxy: {
type: 'jsonp',
url: 'http://MyApp.com/home/index_app',
reader: {
type: 'json',
rootProperty: 'stream'
}
}
}
});
The above correctly shows a list of posts in my view.
I added a controller to push a panel to show the full content of each post, which is working.
Controller
Ext.define('MyAppApp.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
stream: 'homepanel'
},
control: {
'homepanel list': {
itemtap: 'showPost'
}
}
},
showPost: function(list, index, element, record) {
/////// begin code block that solved my problem
var data = record.get('comments');
var comments = '';
Ext.Array.each(data, function(item) {
comments += [item.comment_text] + '<br />';
});
/////// end
this.getStream().push({
xtype: 'panel',
html: [
'<p>' + record.get('post_thumb') + '</p>',
'<p>' + record.get('comments') + '</p>',
comments // added to output HTML
].join(''),
scrollable: true,
styleHtmlContent: true,
});
}
});
My trouble is with retrieving the data from comments, which are nested in the JSON.
With the above controller, I get
[object Object],[object Object]
in my view and in the console I can open those objects and see the entirety of my comments.
But how do I display them in the view? (eg, how do I display "comment_text"?)
Well, they are no longer JSON as soon as they are in your model, they got deserialized to object. To display them you should use a XTemplate. If you already use a template within your view you can directly access the properties of the objects to to render them. Let me know if anything is still unclear.
Why exactly do you render the content by yourself into html property? Is that cause of performance reasons? I am not that used to ST, therefore I ask. Anyway, build up a little helper function that will loop through the comment array and return is as more or less formatted string (this will be up to you, also the check that the array is at least a empty one and never null)
var data = record.get('comments')
function(data) {
var result = '',
len = data.length,
i=0;
for(;i<len;i++) {
result += data[i]['comment_text'] +'<br />'
}
return result;
}
Here is a implementation into the origin function. I post this cause the use of Ext.Array.each is not recommend, because it executes a function for each element and functioncalls within loops should be spared.
showPost: function(list, index, element, record) {
var data = record.get('comments');
function fetchComments(data) {
var result = '',
len = data.length,
i = 0;
for(;i<len;i++) {
result += data[i]['comment_text'] + '<br />';
}
return result;
}
this.getStream().push({
xtype: 'panel',
html: [
'<p>' + record.get('post_thumb') + '</p>',
'<p>' + fetchComments(data) + '</p>'
].join(''),
scrollable: true,
styleHtmlContent: true,
});
}
Here is the other way I have iterated.
Json data:
{
"account" : [
{
"id": "1",
"accNo" : "5869785254",
"curAmt" : "25000",
"balAmt" : "15000",
"transdate" : [
{
"date" : "10",
"month" : "03",
"description" : "Check 232",
"crddbt" : "-1200"
},
{
"date" : "14",
"month" : "03",
"description" : "ATM Withdrawl",
"crddbt" : "-500"
}
],
}
]
}
Sencha Code to iterate on transdate object.
var transDateObj = record.get('transdate');
Ext.Object.each(transDateObj, function(key, value, myself){
Ext.Object.each(value, function(key, value, myself){
console.log(key + ":" + value);
});
});

Getting complex attribute value of object

Given json like this :
{ "rss": {
"page": 1,
"results": [{
"type": "text",
"$": 10
}],
"text": [{
"content": "Lorem ipsum dolor sit amet.",
"author": {
"name": "Cesar",
"email": "cesar#evoria.com"
},
},
{
"content": "Tema Tis rolod muspi merol.",
"author": {
"name": "Cleopatre",
"email": "cleopatre#pyramid.com"
},
}]
}
In javascript, I can retrieve value like this :
var json = JSON.parse(datajson);
$.each(json.text, function(key, val) {
// this one is ok
var content = val['content'];
// this one does not work
var authorname = val['author.name'];
});
Is this a way, given the attribute name in a string format, to retrieve the value of a complex object, for instance json.text[0].author.name?
EDIT
I would like to store the needed attributes in another object like :
[
{ dt: "Text content", dd: "content" },
{ dt: "Author name", dd: "author.name"}
]
You can split your "index" by . and loop over "segments", descending through levels on each iteration.
var obj = {
author : {
name : "AuthorName"
}
}
function get_deep_index(obj, index) {
var segments = index.split('.')
var segments_len = segments.length
var currently_at = obj
for(var idx = 0; idx < segments_len; idx++) {
currently_at = currently_at[segments[idx]]
}
return currently_at
}
console.log(get_deep_index(obj, 'author.name'))
The following should fix the problem.
var authorname = val['author']['name'];
You can also store the object itself as:
var author = val['author'];
And then later on you can index the attributes from that.
console.log(author.name, author.email)
Yent give a good hint in the comments with the eval function. I resolve my needed with this kind of code:
var json = JSON.parse(myjsonasastring);
var descriptiontobeadded = [
{ dt: "Text content", dd: "content" },
{ dt: "Author name", dd: "author.name" }
];
$.each(descriptiontobeadded, function(key, val) {
var dt = '<dt>' + val.dt + '</dt>';
description.append(dt);
var dl = '<dd>' + eval('json.' + val.dd) + '</dd>';
description.append(dl);
});

Categories

Resources