I'm getting too much recursion error at the following piece of code, when I'm running the application on Firefox. The code is expected to create a graphical tree structure in the browser. The method take a Json as an input, traverses through the keys and checks if the value corresponding to the key is "Leaf". If the value is "Leaf", it displays it on the browser and moves on to the next key, else it traverses recursively through the child nodes till the "Leaf" is reached. The node with all its children are displayed on the browser:
function createmasterJson(data) {
var json = '';
for (var index in data) {
var child = data[index];
if (child == 'Leaf') {
json = json + createLeafNode(index);
} else {
if (child.length) {
for (var i = 0; i < child.length; i++) {
json = json + createNonLeafNode(index, createmasterJson(child[i]));
}
} else {
json = json + createLeafNode(index);
}
}
}
return json;
}
function createLeafNode(index){
return '{ "attributes": { "id" :"' + index + '_' + Math.random() +'"}, "data": " '+ index +'" },';
}
function createNonLeafNode(index, child){
return '{ "attributes": { "id" :"' + index + '_' + Math.random() +'"}, "data": " '+ index +'" ,"state": "closed", "children" : ['+child.substring(0, child.length - 1)+']},';
}
Related
const obj = {
"urls": [{
"url": "youtube.com",
"category": ["react js", "javascript"]
},
{
"url": "facebook.com",
"category": ["react js", "javascript"]
}
]
}
const loop = (a) => {
for (let j = 0; j < a.length; j++) {
console.log(a[j].url);
}
return;
}
for (let i in obj) {
console.log(i + " " + loop(obj[i]));
}
The output is:
"youtube.com"
"facebook.com"
"urls undefined"
Why does the loop function get executed first? It should only run inside the second loop:
for(let i in obj){
console.log(i + " " + loop(obj[i]) );
}
I want to be able to output:
urls : youtube.com reactjs,javascript
With short code often the easiest thing to do to debug it is to just do a basic walkthrough of your code by hand to see if it's really doing what you want it to.
You'll notice that the second loop simply performs:
console.log("urls" + " " + loop(obj["urls"]) );
This will result in loop being called:
console.log(obj["urls"][0].url);
console.log(obj["urls"][1].url);
return; // returns undefined
Which will output:
youtube.com
facebook.com
Only then (after the first two logs from inside the loop call) will the initial console.log take place with the return value of loop:
console.log("urls" + " " + undefined /*loop(obj["urls"])*/ );
Giving your last line of output:
urls undefined
As for why loop gets called before the console.log("urls" + ...), think about it, how can console.log know what to output, if to output it it needs to have called loop? loop has to come first.
It sounds like you were trying to do something like this:
const obj = {
"urls": [{
"url": "youtube.com",
"category": ["react js", "javascript"]
},
{
"url": "facebook.com",
"category": ["react js", "javascript"]
}
]
}
// Constructs a string representation of the list of categories
const loop = (a) => {
o = "";
for (let j = 0; j < a.category.length; j++) {
o += "," + a.category[j];
}
return o.substring(1);
}
// Call loop for each url in obj
for (let i in obj.urls) {
console.log("urls : " + obj.urls[i].url + " " + loop(obj.urls[i]));
}
This can be tidied up using join instead of your loop function and by using Array.prototype.forEach:
const obj = {
"urls": [{
"url": "youtube.com",
"category": ["react js", "javascript"]
},
{
"url": "facebook.com",
"category": ["react js", "javascript"]
}
]
}
// Call loop for each url in obj
obj.urls.forEach(urlObj => {
console.log("urls : " + urlObj.url + " " + urlObj.category.join(","));
});
I al using javascript and looping through the values of a submitted form and trying to build a son object out of the form values.
This is an example of the final object I need:
{
"DataObject": {
"user": { "-name": "username" },
"contentFile": {
"-filename": "Breaking_News",
"lock": { "-fileIsBeingEdited": "false" },
"content": {
"line": [
{
"-index": "1",
"-text": "this is the header"
},
{
"-index": "2",
"-text": "this is the first line"
},
{
"-index": "3",
"-text": "this is the second line"
}
]
}
}
}
}
So far i am adding all of this data to a string as that seems to be the only way i can insert the form values (the line array) into the middle of the object.
var jsonStr = '{'
+ 'iceteaDataObject: {'
+ 'user: {"-name": "hindsc52"},'
+ 'contentFile: {'
+ '"-filename": "Ticker",'
+ 'lock: { "-fileIsBeingEdited": "false" },'
+ 'content: {'
+ 'line: ['
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
jsonStr += '{'
jsonStr += "-index: " + i + ',';
jsonStr += "-text: " + elem[i].value;
jsonStr += '},'
}
}
jsonStr += ']}}}}';
console.log(JSON.parse(jsonData));
however when running this I get the error: unexpected token 'i'.
I have tried to use stringily but then just outputs the entire sting again.
You don't need or want JSON for this, just build the object:
// Sample data
var elem = [{
value: "one"
}, {
value: "two"
}];
// Build the object
var obj = {
"DataObject": {
"user": {
"-name": "username"
},
"contentFile": {
"-filename": "Breaking_News",
"lock": {
"-fileIsBeingEdited": "false"
},
"content": {
"line": []
}
}
}
};
var line = obj.DataObject.contentFile.content.line;
elem.forEach(function(entry, index) {
if (entry.value != '') {
line.push({
"-index": index,
"-text": entry.value
});
}
});
// Show result:
document.body.innerHTML =
"<pre>" +
JSON.stringify(obj, null, 2) +
"</pre>";
Side note: You don't check for blank strings like this:
if (!entry.value == '') { // <== Incorrect
You can use:
if (entry.value != '') {
or:
if (entry.value) {
You shouldn't build JSON like this, but use JSON.stringify() (see MDN doc) instead:
var myObject={foo:"bar"};
var myJSON=JSON.stringify(myObject);
console.log(myJSON); //echo {"foo":"bar"}
Here is an alternative way:
var json = {
iceteaDataObject: {
"-name": "hindsc52"
},
contentFile: {
"-filename": "Ticker",
lock: { "-fileIsBeingEdited": "false" },
content: {line: []}
}
}
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
json.contentFile.content.line.push({"-index": i,"-text": elem[i].value }
}
}
var jsonStr = JSON.stringify(json);
You need to put all your keys in quotes for this to work. As the others have pointed out though, you are not really supposed to do this.
If you still want to do it your way, try this:
var jsonStr = '{'
+ '"iceteaDataObject": {'
+ '"user": {"-name": "hindsc52"},'
+ '"contentFile": {'
+ '"-filename": "Ticker",'
+ '"lock": { "-fileIsBeingEdited": "false" },'
+ '"content": {'
+ '"line": ['
for(var i = 0; i < elem.length; i++) {
if(!elem[i].value == '') {
jsonStr += '{'
jsonStr += '"-index": ' + i + ',';
jsonStr += '"-text": ' + '"' + elem[i].value + '"';
jsonStr += '},'
}
}
jsonStr += ']}}}}';
I am trying to fetch objects from a main object. An array in the main object holds
these other objects, I can access the first element by calling 'oData.events.event[0]' but I would like to loop through to get [1], [2], [3] and so on.
//this works
var collection = oData.events.event[0];
$("<li>description: " + collection.description + "</li>").appendTo("#shower");
//this does not work :(
var collection = oData.events.event[0];
var output = "<ul>";
for (var i = 0; i < collection.length; i++)
{
output += "<li>" + collection.description + "</li>";
$(output).appendTo("#shower");
collection = collection + 1 //shift to next array
}
output += "</ul>";
Maybe use a foreach loop
oData.events.event.forEach(function(result) {
console.log(result);
});
Alternatively, try jQuery's .each() function:
$.each(oData.events.event, function(index, value) {
console.log( index + ": " + value );
});
EDIT: It's worth noting that the output of these calls will be an object - you still have to access the data beneath the objects you've looped to!
Fiddle here - however, you can do something like this...
var oData = {
events: {
event: [{ description: '1' },
{ description: '2' },
{ description: '3' }]
}
}
var collection = oData.events.event;
var output = "<ul>";
collection.forEach(function(item, i, arr) {
output += "<li>" + item.description + "</li>";
if (i === arr.length-1) {
output += "</ul>";
$("#shower").append(output);
}
});
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 8 years ago.
I am trying to loop though a JSON object in NODEJS.
I am trying to retrieve the value of for example var value = [table][row][0][STATE] or [table][row][1][STATE] or [table][row][2][STATE] but i am getting STATE undefined error ? Is this the correct way of looping through Json object ?
data = JSON.parse(buffer);
for (var obj in data) {
if (data.hasOwnProperty(obj)) {
console.log(obj);
if (obj == "table") {
for (var prop in data[obj]) {
if (data[obj].hasOwnProperty(prop)) {
console.log(prop + ':' + data[obj][prop][0]['STATE']);
console.log(prop + ':' + data[obj][prop][1]['STATE']);
console.log(prop + ':' + data[obj][prop][2]['STATE']);
console.log(prop + ':' + data[obj][prop][0]['COUNT']);
console.log(prop + ':' + data[obj][prop][0]['COUNT']);
console.log(prop + ':' + data[obj][prop][0]['COUNT']);
}
}
}
}
}
JSON FILE
{
"table":[
{
"row":[
{
"STATE":"A"
},
{
"COUNT":"107"
}
]
},
{
"row":[
{
"STATE":"I"
},
{
"COUNT":"92"
}
]
},
{
"row":[
{
"STATE":"R"
},
{
"COUNT":"2"
}
]
}
]
}
Definitely some odd decisions in your looping. But, try this:
var json = {
"table":[
{ "row":[
{"STATE":"A"},
{"COUNT":"107"}
]
},
{ "row":[
{"STATE":"I"},
{"COUNT":"92"}
]
},
{ "row":[
{"STATE":"R"},
{"COUNT":"2"}
]
}
]
};
var table = json.table;
for( var row in table ) {
for( var field in table[row] ) {
console.log( 'State: ' + table[row][field][0].STATE);
console.log( 'Count: ' + table[row][field][1].COUNT);
}
}
Working jsfiddle: http://jsfiddle.net/pamsvofz/
Update: I'd like to add there really isn't a reason to have the additional row key in the JSON. It really just makes the nesting a little more complicated.
I have the following array
array = [
{
"id": "67",
"sub": [
{
"id": "663",
},
{
"id": "435",
}
]
},
{
"id": "546",
"sub": [
{
"id": "23",
"sub": [
{
"id": "4",
}
]
},
{
"id": "71"
}
]
}
]
I am currently looping throught the array as follows
calling the array:
processArray(array);
the function loop
function processArray(arr)
{
for(var item in arr) {
var value = arr[item];
var order = item;
var itemID = value.id;
if(itemID != null)
{
$('.text').append(" ORDER : " + order + " Item ID : " + itemID + "<br />" );
}
if(typeof(value) == 'object') { //If it is an array,
processArray(arr[item]);
}
}
}
Currently i am getting the order of the item and the current ID no problem. What i need however (for my database schema) is for each item get the ID of its parent if there is one.
Do i need to pass the parent to each node? Or is there an easier way?
Thanks
Working demo
Include an optional parameter parentID in the function; by doing this, you can still use the processArray(array); syntax to process the original array.
function processArray(arr, parentID)
{
for(var item in arr) {
var value = arr[item];
var order = item;
var itemID = value.id;
if(itemID != null)
{
var output = " ORDER : " + order + " Item ID : " + itemID;
if( parentID ) { output += " PARENT : " + parentID; }
$('.text').append( output + "<br />");
}
// PROCESS SUB-ARRAY
if( typeof(value.sub) == 'object') { //If it is an array,
processArray( value.sub, itemID );
}
}
}
Use an auxiliary function that has id as part of its signature:
function processArray(arr) {
function _processArray(arr, id) {
for (var item in arr) {
var value = arr[item];
var order = item;
var itemID = value.id; // you need to change this because on the second call you pass in a string and not just an object
var parentId = id;
// Commenting the if statement that you had here actually shows the parent id's now.
$('.text').append(" ORDER : " + order + " Item ID : " + itemID + " Parent Id : " + parentId + "<br />");
if (typeof value === "object") { //use instanceof,
_processArray(arr[item], itemID);
}
}
}
_processArray(arr, 0);
}