JSON to HTML using JSON.parse undefined error - javascript

When trying to parse the JSON
[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]
into a list for navigation its just returning undefined.
I was using code from another answer which was working fine with hardcoded JSON but when using it from a textbox (as its going to be generated using jquery.nestable.js) it just gived undefined and i cant see why, ive tried escaping the quotation marks too but no luck there.
function convertNav(){
var data = document.getElementById('jsonNav').value;
var jsn = JSON.parse(document.getElementById('jsonNav').value);
var parseJsonAsHTMLTree = function(jsn){
var result = '';
if(jsn.title && jsn.children){
result += '<li>' + jsn.title + '<ul>';
for(var i in jsn.children) {
result += parseJsonAsHTMLTree(jsn.children[i]);
}
result += '</ul></li>';
}
else {
result += '<li>' + jsn.title + '</li>';
}
return result + '';
}
var result = '<ul>'+parseJsonAsHTMLTree(jsn)+'</ul>';
document.getElementById('convertedNav').value = result;
}
Ive put it in a jsfiddle
http://jsfiddle.net/nfdz1jnx/

Your code handles only a single Javascript object but, according to your code, all nodes and sub-nodes are wrapped inside Javascript arrays. You can use Array.prototype.forEach to handle the array objects.
Sample code follows.
function convertNav() {
var data = document.getElementById('seriaNav').value;
var jsn = JSON.parse(document.getElementById('seriaNav').value);
var parseJsonAsHTMLTree = function(jsn) {
var result = '';
jsn.forEach(function(item) {
if (item.title && item.children) {
result += '<li>' + item.title + '<ul>';
result += parseJsonAsHTMLTree(item.children);
result += '</ul></li>';
} else {
result += '<li>' + item.title + '</li>';
}
});
return result + '';
};
var result = '<ul>' + parseJsonAsHTMLTree(jsn) + '</ul>';
document.getElementById('convertedNav').value = result;
}
<textarea class="span7" style="width:400px;height:100px;" id="seriaNav">[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]</textarea>
<hr />
<button class="btn btn-primary" onClick="convertNav();return false;">Convert</button>
<hr />
<textarea class="span5" style="width:400px;height:100px;" id="convertedNav"></textarea>

Your jsn variable is an array. You're getting a list of Objects back and you'll need to parse each one.
Add this after you get jsn back and you'll see an example of retrieving your data.
alert(jsn[0].title);

Your JSON is parsed into an array of objects. With this in mind, your paths to extract information are wrong. For example, you have:
if(jsn.title...
...whereas there is no jsn.title. There is, however, json[0].title.
Basically, you're missing a loop, over the objects. After
var result = '';
add
for (var i=0, len=jsn.length; i
...and in code subsequent to that change all references to jsn to jsn[i]
And of course close the loop further down.
(Finally, at the risk of being pedantic, jsn is not the best name for the var; it's not JSON anymore; it used to be, but now it's parsed, so it's an array. JSON is a string.)

[{"title":"First Item","href":"first","children":[{"title":"Sub First Item","href":"sub"}]},{"title":"Second Item","href":"home"}]
This is not JSON, this is an array of objects. You don't need to parse this. It's already parsed. It's a javascript object.
You should be able to just parse it like you would a regular object.
data[0].title
data[0].children[1].title
etc.

Related

JSON.parse() returning strings

I am trying to iterate through an array of objects and populate an HTML select element with options whose values are the entire contents of each object. The population is successful, but the objects are turned into strings in the process and I do not know how to turn them back into objects.
Running them through JSON.parse() gives me "Uncaught SyntaxError: Unexpected token o in JSON at position 1 at JSON.parse." My research suggests that this happens when you use JSON.parse() on something that is already an object, but running typeOf() on the data beforehand reveals that it is a string.
I do not get this error if I instead run the data through JSON.parse(JSON.stringify(data)), but its output remains a string.
Please help me understand what I am misapprehending about JSON.parse(). Thank you.
const selectors = document.getElementsByClassName("ingredientSelector");
const cookButton = document.getElementById("cookButton");
//very large array of ingredient objects
let selectorOptions = "<option value = 'Nothing'>Nothing</option>";
for (let i = 0; i < ingredients.length; i++){
selectorOptions += ("<option value = '" + ingredients[i] + "'>" + ingredients[i].name + "</option>");
}
Array.prototype.forEach.call(selectors,function(selector){
selector.innerHTML = selectorOptions;
});
function cook(ingredients){
console.log("Cooking with ingredients: " + ingredients);
}
cookButton.addEventListener("click", function(){
let ingredients = [];
Array.prototype.forEach.call(selectors,function(selector){
if(selector.value !== 'Nothing'){
console.log(typeof(selector.value))
JSON.parse(selector.value);
let JSONString = JSON.stringify(selector.value);
console.log(typeof(JSONString));
let JSONObject = (JSON.parse(JSONString));
console.log(typeof(JSONObject));
console.log(JSONObject.name);
}
console.log(ingredients);
cook(ingredients);
});
});
The issue is how you're building the value properties for the options you're inserting into each selector. On this line:
selectorOptions += ("<option value = '" + ingredients[i] + "'>" + ingredients[i].name + "</option>");
Your comment says that ingredients is an array of objects, so ingredients[i] will be an object. Concatenating an object to a string will, by default, turn it into [object Object] - and this is what's causing your error. You're ending up with an option that looks something like this, perhaps:
<option value = '[object Object]'>Raw Prime Meat<object>
There's two perfectly valid approaches here. You can either store the ingredient index in the option values, which you can then use to lookup the ingredient from your master array later, or you should use JSON.stringify(ingredients[i]) to turn the object into a JSON.parseable string to make your code work as-is.
So this would work fine:
selectorOptions += ("<option value = '" + JSON.stringify(ingredients[i]) + "'>" + ingredients[i].name + "</option>");

Concat In JavaScript

For some reason the keyText variable isn't showing any value when it should concat for each variable in keywords.
When someone clicks the button it runs addKeyword and grabs the value of the input.
Tried to Console.Log the keyText variable and didn't work at all.
var keywords = [];
var keyText = "";
function addKeyword() {
var keywordName = document.getElementById("keywordAdd").value
keywords.push(keywordName);
keywords.forEach(showKeywords);
function showKeywords(item, index) {
var newString = "<span class='keyword' onclick='delKeyword(" + index + ")'>✖ " + item + "</span>";
keyText.concat(newString);
document.getElementById("keywords").innerHTML = keyText;
}
}
No Errors shown in Console. Expected result is a list of but doesn't show.
The problem is that .concat doesn't mutate the string, it returns a new string.
You need to do something like this:
keyText = keyText.concat(newString);
By the way, your current approach is not that efficient because it changes the element's inner HTML at each iteration. You should probably do that only once after the HTML for all the elements is generated. Here is another approach that does that:
const result = keywords.map((item, index) => (`<span class="keyword" onclick="delKeyword(${index})">✖ ${item}</span>`)).join('');
document.getElementById("keywords").innerHTML = result;
Titus answer is correct, but you can simply use :
keyText += newString;

Javascript getting object properties

I want to create a google.Visualization.DataTablein the end, to show a graph. By now, I have a Problem with the following:
This is my code for getting Object from JSON-string and listing Properties:
var jsonData = <?php echo "'". $jsonTable. "'"; ?>;
var parsed = JSON.parse(jsonData);
var sensors = [];
for (var x in parsed){
sensors.push(parsed[x]);
}
var text ="";
for (var sensor in sensors){
if (sensors.hasOwnProperty(sensor)){
var measures = sensors[sensor];
text += ('\r\n' + sensor);
for (var time in measures){
if(measures.hasOwnProperty(time)){
text += ('\r\n' + time + " = " + measures[time]);
}
}
}
}
$(document.getElementById('chart_div')).text(text);
And my jsonData looks like this:
jsonData = '{"sensor1":
{"Date(2016,1,08,10,30,03)":19.187,
"Date(2016,1,08,10,00,02)":18.937[,...]},
"sensor2":
{"Date(2016,1,08,10,30,04)":18.687,
"Date(2016,1,08,10,00,03)":18.437[,...]}
[,...]}'
My Problem is that i don't get the values "sensor1", "sensor2" and so on in the loop. text += ('\r\n' + sensor); only returns the index of the sensor-object in the sensors-object.
How can I get the sensor name instead of the index?
One simple workaround
Remove the var sensors = [];
Find sensors and replace with parsed.
Code:
for (var sensor in parsed){
if (parsed.hasOwnProperty(sensor)){
var measures = parsed[sensor];
text += ('\r\n' + sensor);
console.log(parsed);
for (var time in measures){
if(measures.hasOwnProperty(time)){
text += ('\r\n' + time + " = " + measures[time]);
}
}
}
How can I get the sensor name instead of the index?
You need to do something with the property name in your first loop.
At present you are taking the property name (sensor1), using it to get the value ({"Date...) and then putting the value in an array while discarding the property name.
The simplest option would be to get rid of your first loop entirely and work with parsed instead of sensors in your second loop.

searching deeper than 1 into json

im trying to figure out how to search deeper than just one deep in my JSON file.
its structure is as follows
json>data>movies>
in movies the different movies are enumerated 0, 1, 2, 3, 4, etc so
json>data>movies>3>
would contain movie information for the 4th movie
each containing key value pairs.the code i am using only seems to look one deep, and i cant seem to get it to go deeper.
code is as follows
$('#search').keyup(function () { // i understand this to watch the form id search
var searchField = $('#search').val(); // sets variable searchfield from typed content, .val grabs the content
if (searchField.length) // this sets the length to false by default ensuring the code only runs when it is supposed to and not all the time
{
var myExp = new RegExp(searchField, "i"); // sets variable myexp to regular expression using "i" for case insensitive
var found = 0; // sets variable found to 0 to keep div hidden until match is found
$.getJSON('/secure/movies.json', function (data) { //gets movies.json file pushes to data function
var output = '<ul class="searchresults">';
$.each(data, function (key, val) { // this should make key pairs from data
if (val.title.search(myExp) !== -1) { // this is the problem i think
console.log(val); // this should show our search term results in console
found = 1;
output += '<li>';
output += '<h2>' + val.title + '</h2>';
output += "<a href=" + val.image + ' target="_blank" ></a>';
output += '</li>';
}
});
output += '</ul>';
if (found == 1) {
$('#update').removeClass('update-hidden');
$('#update').html(output);
} else {
$('#update').addClass('update-hidden');
}
});
} else {
$('#update').addClass('update-hidden');
}
});
ive tried manipulating val.title.search(myexp) but i might be missing the boat on whats happening here with val.title.search. thanks in advance

Javascript Objects to XML String with multiple levels

I have a multi-dimensional Javascript Object that I can easily convert to a JSON string using a .stringify method. I'm trying to write a function to do something similar but in an XML, markup, format. The catch is I want it to be able to handle any number of dimensions.
Let's say I have the following the multi-dimensional object with values like so:
object['annualrevenues']['option0']['ID'] = 1;
object['annualrevenues']['option0']['text'] = '$50mil';
object['annualrevenues']['option1']['ID'] = 2;
object['annualrevenues']['option1']['text'] = '$100mil';
object['annualrevenues']['option2']['ID'] = 3;
object['annualrevenues']['option2']['text'] = '$200mil';
I want to build a string like so:
var xmlText = <xml><annualrevenues><option0><ID>1</ID><text>$50</text></option0></annualrevenues></xml>
That once returned as a response with contentType 'XMLDOC' will look like this:
<xml>
<annualrevenues>
<option0>
<ID>1</ID>
<text>$50</text>
</option0>
</annualrevenues>
</xml>
So I have the following function:
var xmlText = '<xml>';
xmlText += formatXMLSubObjects(objText,xmlText);
function formatXMLSubObjects(objText,xmlText){
for (prop in objText) {
if (typeof objText[prop] == 'object') {
xmlText += '<'+prop+'>';
for (subProp in objText[prop]) {
if (typeof objText[prop][subProp] == 'object') {
// Run the function again as recursion
xmlText += formatXMLSubObjects(objText[prop][subProp],xmlText);
}
else {
xmlText += '<' + subProp + '>' + objText[prop][subProp] + '</' + subProp + '>';
}
}
xmlText += '</'+prop+'>';
}
else {
xmlText += '<'+prop+'>'+objText[prop]+'</'+prop+'>';
}
}
return xmlText;
}
The problem is when the formatXMLSubObjects function returns from the second call, the original object in the first call has been overwritten and is now undefined.
Anyone able to help with this?
Move the definition of xmlText inside the function and use another variable outside to contain the initial payload, and also local variables in the for loops, otherwise they are considered global and overwritten, and don't pass your xmlText ahead to the call, but simply concatenate the result with the previous one every time.
function formatXMLSubObjects(objText) {
var xmlText = ""; // this will contain only this chunk of the object
for (var prop in objText) {
xmlText += '<'+prop+'>'; // place the tag anyway
if (typeof objText[prop] == 'object') {
xmlText += formatXMLSubObjects(objText[prop]); // if it's an object recurse
} else {
xmlText += objText[prop]; // ... otherwise just add the value (this will work only for simple values
}
xmlText += '</' + prop + '>';
}
return xmlText;
}
var xml = '<xml>';
xml += formatXMLSubObjects(obj);
xml += '</xml>';
Take a look at this fiddle: http://jsfiddle.net/vZjAP/

Categories