I am trying to parse a JSON and build a HTML string to append to the DOM but no matter what I do the string is only returning the first element in the JSON.
Here's the js:
var menu_json = {
"name": "Personal Banking",
"url": "/test1.html",
"children": [
{
"id": "1",
"name": "test2",
"url": "/products/deposits/test2.html",
"children": [
{
"id": "1",
"name": "test3",
"url": "/products/deposits/test3.html",
"children": [
{
"id": "1",
"name": "test5",
"url": "test5"
},
{
"id": "2",
"name": "test6",
"url": "/products/deposits/test6.html"
},
{
"id": "3",
"name": "test7",
"url": "/products/deposits/test7.html"
},
{
"id": "4",
"name": "test8",
"url": "/products/deposits/test8.html"
},
{
"id": "5",
"name": "test9",
"url": "/products/deposits/test9.html"
},
{
"id": "6",
"name": "test10",
"url": "/products/deposits/test10.html"
},
{
"id": "7",
"name": "test11",
"url": "/products/deposits/test11.html"
}
]
}
]
}
]
}
var test_html = "<ul>",
buildNavHelper = function(curNode){
test_html += "<li>" + curNode.name;
if (curNode.hasOwnProperty('children')){
test_html += "<ul>" + _.map(curNode.children, buildNavHelper) + "</ul>";
}
test_html += "</li>";
};
buildNavHelper(menu_json);
test_html += "</ul>";
$('#thing').append(test_html);
Heres a fiddle
https://jsfiddle.net/w734bvw7/
buildNavHelper() has no return statement, so there's nothing coming back from _.map(). The outer test_html isn't in scope. Try this:
buildNavHelper = function(curNode){
var test_html = "<li>" + curNode.name;
if (curNode.hasOwnProperty('children')){
test_html += "<ul>" + _.map(curNode.children, buildNavHelper).join("") + "</ul>";
}
test_html += "</li>";
return test_html;
};
test_html = "<ul>" + buildNavHelper(menu_json) + "</ul>";
Note the addition of .join() to avoid having commas in your output.
Also, there's no need to use underscore here; Array.map() is native Javascript.
buildNavHelper = function(curNode){
var test_html = "<li>" + curNode.name;
if (curNode.hasOwnProperty('children')){
test_html += "<ul>" + curNode.children.map(buildNavHelper).join("") + "</ul>";
}
test_html += "</li>";
return test_html;
};
https://jsfiddle.net/w734bvw7/3/
buildNavHelper = function(curNode){
var test_html = "<ul>";
test_html += "<li>" + curNode.name;
if (curNode.hasOwnProperty('children')){
test_html += "<ul>" + _.map(curNode.children, buildNavHelper) + "</ul>";
}
test_html += "</li>";
test_html += "</ul>";
return test_html;
};
$('#thing').append(buildNavHelper(menu_json));
Building the list using HTML strings can produce HTML injection. I recommend DOM methods instead:
function buildNavHelper(arr) {
var ul = document.createElement('ul');
for(var i=0; i<arr.length; ++i) {
var li = document.createElement('li');
li.appendChild(document.createTextNode(arr[i].name));
if(arr[i].children)
li.appendChild(buildNavHelper(arr[i].children));
ul.appendChild(li);
}
return ul;
}
var menu_json = {
"name": "Personal Banking",
"url": "/test1.html",
"children": [
{
"id": "1",
"name": "test2",
"url": "/products/deposits/test2.html",
"children": [
{
"id": "1",
"name": "test3",
"url": "/products/deposits/test3.html",
"children": [
{
"id": "1",
"name": "test5",
"url": "test5"
},
{
"id": "2",
"name": "test6",
"url": "/products/deposits/test6.html"
},
{
"id": "3",
"name": "test7",
"url": "/products/deposits/test7.html"
},
{
"id": "4",
"name": "test8",
"url": "/products/deposits/test8.html"
},
{
"id": "5",
"name": "test9",
"url": "/products/deposits/test9.html"
},
{
"id": "6",
"name": "test10",
"url": "/products/deposits/test10.html"
},
{
"id": "7",
"name": "test11",
"url": "/products/deposits/test11.html"
}
]
}
]
}
]
}
function buildNavHelper(arr) {
var ul = document.createElement('ul');
for(var i=0; i<arr.length; ++i) {
var li = document.createElement('li');
li.appendChild(document.createTextNode(arr[i].name));
if(arr[i].children)
li.appendChild(buildNavHelper(arr[i].children));
ul.appendChild(li);
}
return ul;
}
document.querySelector('#thing').appendChild(buildNavHelper([menu_json]));
<div id="thing"></div>
Related
I've a scenario where I've to iterate two list or arrays to get required values. So I am doing something like this:
var html = "";
$.each(list, function (i, set1) { //set1 is a list or array
$.each(set1.Tabs, function (i, set2) { //set1.Tabs is another one
html += "<li><a href='#" + set2.TabName + "'>" + set2.Details + "</a> <span class='ui-icon ui-icon-close' role='presentation'>Remove Tab</span></li>";
})
})
The above works fine, it returns me the required data. But the problem is, say the outer loop has 10 values and the inner loop has four values. So the inner loop gets iterated ten times with the four values. This is natural and it should do. I was trying to get distinct values using the following (For the outer loop specifically):
list = list.filter((x, i, a) => a.indexOf(x) === i);
Though the above should work, my expected output is as follows:
Input: [1, 2, 3, 3, 4, 5, 6, 6]
Output: [1, 2, 3, 4, 5, 6]
N.B: My concern is with the inner loop, not with the outer one. But to iterate the inner loop, I've to go through the outer loop. Is there any way I can get the inner loop work directly?
Update 1: Sample Code
$(document).ready(function() {
var html = "";
var data = [{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" }
]
}
]
$.each(data, function(i, set1) { //set1 is a list or array
$.each(set1.topping, function(i, set2) { //set1.Tabs is another one
html += "<li><a href='#" + set2.id + "'>" + set2.type + "</a> <span class='ui-icon ui-icon-close' role='presentation'>Remove Tab</span></li>";
})
})
$('#add').append(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="add"></div>
You can create unique toppings based on the id and then render the list using unique toppings. To create unique toppings, you can use flatMap() Object.values() and array#reduce.
$(document).ready(function() {
var html = "";
var data = [{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"topping": [{
"id": "5001",
"type": "None"
},
{
"id": "5002",
"type": "Glazed"
},
{
"id": "5005",
"type": "Sugar"
},
{
"id": "5007",
"type": "Powdered Sugar"
}
]
},
{
"id": "0002",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"topping": [{
"id": "5001",
"type": "None"
},
{
"id": "5002",
"type": "Glazed"
},
{
"id": "5005",
"type": "Sugar"
},
{
"id": "5007",
"type": "Powdered Sugar"
}
]
}
]
const uniqueToppings = Object.values(data
.flatMap(o => o.topping)
.reduce((r, {id, type}) => {
r[id] = r[id] || {id, type};
return r;
},{}));;
$.each(uniqueToppings, function(i, set) {
html += "<li><a href='#" + set.id + "'>" + set.type + "</a> <span class='ui-icon ui-icon-close' role='presentation'>Remove Tab</span></li>";
});
$('#add').append(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="add"></div>
The idea is to take a JSON array, loop through each of the entries for planets and output them to an unordered list, with one entry per li. All works well in this instance.
I have successfully written a method to output nested JSON when the JavaScript file contains the JSON array and the code below it, but I am having serious trouble identifying a method to retrieve the same data from an external .json file, using AJAX.
Here is the working local version.
<ul id="object-list"></ul>
$(document).ready( function() {
var sol_sys = [];
sol_sys = {
"stars": [
{ "name": "Sun", "object": "Star", "url": "stars/sun" }
],
"planets": [
{ "name": "Mercury", "object": "Planet", "parent": "Sun", "url": "planets/mercury" },
{ "name": "Venus", "object": "Planet", "parent": "Sun", "url": "planets/venus" },
{ "name": "Earth", "object": "Planet", "parent": "Sun", "url": "planets/earth" },
{ "name": "Mars", "object": "Planet", "parent": "Sun", "url": "planets/mars" },
{ "name": "Ceres", "object": "Dwarf Planet", "parent": "Sun", "url": "planets/ceres" },
{ "name": "Jupiter", "object": "Planet", "parent": "Sun", "url": "planets/jupiter" },
{ "name": "Saturn", "object": "Planet", "parent": "Sun", "url": "planets/saturn" },
{ "name": "Uranus", "object": "Planet", "parent": "Sun", "url": "planets/uranus" },
{ "name": "Neptune", "object": "Planet", "parent": "Sun", "url": "planets/neptune" },
{ "name": "Pluto", "object": "Dwarf Planet", "parent": "Sun", "url": "planets/pluto" },
{ "name": "Eris", "object": "Dwarf Planet", "parent": "Sun", "url": "planets/eris" }
],
"moons": [
{ "name": "Luna", "object": "Moon", "parent": "Earth", "url": "moons/luna" },
{ "name": "Callisto", "object": "Moon", "parent": "Jupiter", "url": "moons/callisto" },
{ "name": "Ganymede", "object": "Moon", "parent": "Jupiter", "url": "moons/ganymede" },
{ "name": "Io", "object": "Moon", "parent": "Jupiter", "url": "moons/io" },
{ "name": "Europa", "object": "Moon", "parent": "Jupiter", "url": "moons/europa" },
{ "name": "Enceladus", "object": "Moon", "parent": "Saturn", "url": "moons/enceladus" },
{ "name": "Titan", "object": "Moon", "parent": "Saturn", "url": "moons/titan" },
{ "name": "Miranda", "object": "Moon", "parent": "Uranus", "url": "moons/miranda" },
{ "name": "Triton", "object": "Moon", "parent": "Neptune", "url": "moons/triton" },
{ "name": "Charon", "object": "Moon", "parent": "Pluto", "url": "moons/charon" }
]
}
var x = [];
$.each(sol_sys.planets, function(index) {
x += '<li>' + sol_sys.planets[index].name + '</li>';
});
$('#object-list').append(x);
});
However, I have spent the past two days trying to figure out the method to achieve this, with the JSON kept separate in a separate .json file.
Here is an example of one method I have tried:
$(document).ready( function() {
var sol_sys = $.getJSON('assets/data.json');
var x = [];
$.each(sol_sys.planets, function(index) {
x += '<li>' + sol_sys.planets[index].name + '</li>';
});
$('#object-list').append(x);
});
This code successfully fetches the data as can be seen in the console, but it also spits out this error message:
Uncaught TypeError: Cannot read property 'length' of undefined
I am thinking that there is something obvious that I have completely missed. I have also tried the method demonstrated here, with exactly the same outcome.
Can anybody point me in the right direction?
Thanks!
$.getJSON is an async call - so you need to use the callback function to access the returned data:
$.getJSON('assets/data.json', function(sol_sys) {
var x = [];
$.each(sol_sys.planets, function(index) {
x += '<li>' + sol_sys.planets[index].name + '</li>';
});
$('#object-list').append(x);
});
Hi you can do it this way:
your ajax:
function getList() {
return $.ajax({
type: "GET",
url: "YourUrl"
})
}
call it like this:
getList().done(function(response){
var data=JSON.parse(response);
if (data != null) {
jQuery.each(data, function(index, value){
//use an id in your ul in order to append some items
$("#yourUl id").append('<li><a href=' + value.url+ '>' + value.name+ '</a></li>');
});
}
})
Or
$.getJSON( 'assets/data.json').done(function(response) {
var data=JSON.parse(response);
if (data != null) {
jQuery.each(data, function(index, value){
//use an id in your ul in order to append some items
$("#yourUl id").append('<li><a href=' + value.url+ '>' + value.name+ '</a></li>');
});
}
})
Edit: append the elements like this:
$.getJSON( 'data.json').done(function(response) {
jQuery.each(response, function(index, value){
$("#planetList").append('<li>'+index+'</li>');
jQuery.each(value, function(index2, value2){
$("#planetList").append('<ul><li><a href=' +value2.url+ '>' +value2.name+ '</a></li>')
console.log(value2);
})
$("#planetList").append('<ul>');
})
})
Hope it helps
I have a time calculation tool which you can find in the following fiddle link. Once someone has selected a platform, task type, component and number of units, the number of units entered should be multiplied with selected component value and show it on the below table. I have managed to get the all populated values but can't do the math. I have tried several attempts but it wasn't working.
var myJson = {
"platforms": [
{
"name": "Sitecore",
"id": "sitecore",
"tasktype": [
{
"name": "Promobox",
"id": "promobox",
"components": [
{
"name": "Accordion",
"id": "accordion",
"time": "20"
},
{
"name": "Box 1",
"id": "box1",
"time": "30"
}
]
},
{
"name": "Video",
"id": "video",
"components": [
{
"name": "Box 2",
"id": "box2",
"time": "25"
},
{
"name": "Box 3",
"id": "box3",
"time": "30"
}
]
}
]
},
{
"name": "Siab",
"id": "siab",
"tasktype": [
{
"name": "Newswire",
"id": "newswire",
"components": [
{
"name": "Box 4",
"id": "box5",
"time": "50"
},
{
"name": "Box 5",
"id": "box5",
"time": "40"
}
]
},
{
"name": "Task Type New",
"id": "tasktypenew",
"components": [
{
"name": "Box 6",
"id": "box6",
"time": "20"
},
{
"name": "Box 7",
"id": "box7",
"time": "100"
}
]
}
]
}
]
};
$.each(myJson.platforms, function (index, value) {
var platform_id;
var tasktype_id;
var component_id;
$("#platform").append('<option rel="' + index + '" value="' + value.id + '">' + value.name + '</option>');
$("#platform").change(function () {
$("#tasktype, #component").find("option:gt(0)").remove();
$("#tasktype").find("option:first").text("Loading...");
platform_id = $(this).find('option:selected').attr('rel');
$.each(myJson.platforms[platform_id].tasktype, function (index1, value1) {
$("#tasktype").find("option:first").text("Select Task Type");
$("#tasktype").append('<option rel="' + index1 + '" value="' + value1.id + '">' + value1.name + '</option>');
});
});
$("#tasktype").change(function () {
$("#component").find("option:gt(0)").remove();
$("#component").find("option:first").text("Loading...");
tasktype_id = $(this).find('option:selected').attr('rel');
$.each(myJson.platforms[platform_id].tasktype[tasktype_id].components, function (index2, value2) {
$("#component").find("option:first").text("Select Component");
$("#component").append('<option rel="' + index2 + '" value="' + value2.time + '">' + value2.name + '</option>');
});
});
});
$(document).ready(function () {
$('#calculate').click(function () {
$('#calc input, #calc select').each(
function (index) {
var input = $(this);
$('#data tbody').append('<tr><td>' + input.val() + '</td></tr>');
});
});
});
JS Fiddle
Ok this took a lot of debugging. You were building your table wrong and not storing data properly. The whole fishing for data was problematic. Here is the debugged calculator:
$(document).ready(function () {
$('#calculate').click(function () {
let tr = $("<tr/>").appendTo("#data tbody");
console.log(tr);
$('#calc input, #calc select').each( function (index) {
console.log($(this));
var input = $(this);
$(tr).append('<td class=row-'+ $(input).attr("id") + '>' + input.val() + '</td>');
});
const componentFactor = $(tr).children(".row-component").text();
const units = $(tr).children(".row-units").text();
const total = componentFactor*units;
$(tr).append('<td>' + total + '</td>');
});
});
notice:
Change of table structure format.
Now appending td's to single tr each time in order to sustain table-row consistency.
Fishing data from row with the help of adding class tag identifier to each td
Showing result.
update fiddle link:
https://jsfiddle.net/x4rLuf88/1/
I've some json files included in the page like this:
<script type="text/javascript" language="javascript" src="json/divaniModerni.json"></script>
<script type="text/javascript" language="javascript" src="json/divaniClassici.json"></script>
All of them having same structure, containing different elements:
var divaniModerni = {
"modelli": [
{
"nome": "California",
"num": "5",
},
{
"nome": "Terra",
"num": "6",
},
{
"nome": "Laura",
"num": "7",
},
{
"nome": "Nonstop",
"num": "11",
},
{
"nome": "Venere",
"num": "8",
},
{
"nome": "Comfort",
"num": "5",
},
{
"nome": "Infinity",
"num": "8",
},
]
}
I'm now able to parse the file like this:
$(divaniModerni.modelli).each(function(index, element){ (...) }
but it's possible to dinamically change the file to parse passing the name to a function, like this?
function show(category)
{
$(category.modelli).each(function(index, element){ (...) }
}
show(divaniModerni);
I've tried with:
$(window[category].modelli).each(function(index, element){ (...) }
but It's not working...
EDIT:
Inside the each I'm dinamically creating a row on a table, based on the selected json elements:
$(divaniModerni.modelli).each(function(index, element){
if (i == 1)
riga += "<tr>";
riga += "<td><figure><a class='anteprime' rel='prettyPhoto[gallery" + i + "]' href='images/divani/" + element.nome + ".jpg'><img src='images/anteprima/divani/" + element.nome + ".jpg' alt='" + element.nome + "'></a><div class='descrizione'>" + element.nome;
if (element.num > 0)
{
for (j = 2; j <= element.num; j++)
{
riga += "<a style='display:none;' class='anteprime' rel='prettyPhoto[gallery" + i + "]' href='images/divani/" + element.nome + j + ".jpg'><img src='images/anteprima/divani/" + element.nome + j + ".jpg' alt='" + element.nome + "'></a>";
}
}
riga += "</div></figure></td>";
if (i == categoria.modelli.length)
{
riga += "</tr>";
$('#mostra').append(riga);
}
else if (i % 4 == 0)
{
riga += "</tr>";
$('#mostra').append(riga);
riga = "<tr>";
}
i++
})
Pass in the object reference directly into the each statement to only iterate on that.
http://jsfiddle.net/b3zdahc0/
var divaniModerni = {
"modelli": [
{
"nome": "California",
"num": "5",
},
{
"nome": "Terra",
"num": "6",
},
{
"nome": "Laura",
"num": "7",
},
{
"nome": "Nonstop",
"num": "11",
},
{
"nome": "Venere",
"num": "8",
},
{
"nome": "Comfort",
"num": "5",
},
{
"nome": "Infinity",
"num": "8",
}
]
};
function show(category)
{
$.each(category.modelli, function(index, element) {
alert(index)
});
}
$("button").on("click", function(e) {
show(divaniModerni);
});
In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)