Can some one help me make the following JSON data:
{
"main": {
"label":"Main",
"url":"#main"
},
"project": {
"label":"Project",
"url":"#project"
},
"settings": {
"label":"Settings",
"url":"#settings",
"subnav":[
{
"label":"Privacy",
"url":"#privacy"
},
{
"label":"Security",
"url":"#security"
},
{
"label":"Advanced",
"url":"#advanced"
}
]
}
}
into the following bullets list using JS? Assuming you don't know what the first nodes are call labeled (e.g. "main", "project" <- these will be dynamically generated):
Main (#main)
Project (#project)
Settings (#settings)
Privacy (#privacy)
Security (#security)
Advanced (#advanced)
Thanks
Let's not use HTML string-hacking, shall we? That would break as soon as any of the data had characters like < or & in (or " in attribute values). Use DOM methods and you don't have to worry about character escaping:
function createNav(navs) {
var ul= document.createElement('ul');
for (name in navs) {
var nav= navs[name];
var a= document.createElement('a');
a.href= nav.url;
a.appendChild(document.createTextNode(nav.label));
var li= document.createElement('li');
li.id= 'nav-'+name;
li.appendChild(a)
if ('subnav' in nav)
li.appendChild(createNav(nav.subnav));
ul.appendChild(li);
}
return ul;
}
document.getElementById('navcontainer').appendChild(createNav(jsondata));
Most JS frameworks offer shortcuts to make this a bit less wordy. For example with jQuery:
function createNav(navs) {
var ul= $('<ul>');
for (name in navs) {
var nav= navs[name];
var li= $('<li>', {id: name});
li.append($('<a>', {href: nav.url, text: nav.label}));
if ('subnav' in nav)
li.append(createNav(nav.subnav));
ul.append(li);
}
}
$('#navcontainer').append(createNav(jsondata));
Note that either way, you're using an Object literal which means you get no control over the order the list of navs comes out. You have no guarantee that main will be above project. If you want a defined order, you will have to have the returned JSON data be an array.
My code is on JSfiddle.
As JSON parser I used this one.
The main code is a recursive renderer of the parsed JSON:
function recursive_parse(result) {
var html = '<ul>';
for (var k in result) {
html = html + '<li>' + result[k].label + ' (' + result[k].url + ')';
html = html + recursive_parse(result[k].subnav);
html = html + '</li>';
}
html = html + '</ul>';
return html;
}
var result = json_parse($("div#test1111").html());
var html = recursive_parse(result);
$("div#test2222").html(html);
Related
I wrote an custom API(node.js app) that gets the info about the blogs from medium.com, right now there is
the author/main pic of the article,
title,
link to the article on medium.com(redundant),
the entire article text, in the JSON output.
Sample API/JSON:
{
"img": [
"https://upload.wikimedia.org/wikipedia/commons/4/42/Blog_%281%29.jpg"
],
"title": [
"The old and the new or not so new: Java vs JavaScript"
],
"link": [
"https://medium.com/#aki9154/the-old-and-the-new-or-not-so-new-java-vs-javascript-760f84e87610?source=rss-887f1b1ddb75------2"
],
"desc": [
"<p>It’s funny how the name JavaScript makes you believe that it is somehow..."
]
}
Then i am polling this API/JSON and spitting out the output in a thumbnail format, basic html for now(no design/CSS).
Where i am stuck is when a user clicks on a thumbnail and i need to make sure that i display the correct article?!
For which i need to display a new page when the thumbnail/article is clicked, i can use #4 from JSON above as an output for that dynamically created new page and put it out nicely)
The issue that i am facing now is how to dynamically produce the correct article when the dynamically created link is clicked?
Right now nothing happens when i click on the thumbnail and that's what this project link displays...
I did some stackoverflow research and read some jQuery docs(event propagation and more...) and was able to make changes to the index.js, below is how it looks like but nothing works, any help will be appreciated...
index.js:
$(function () {
var desc = "";
function newWin() {
var w = window.open();
$(w.document.body).html('<p>'+desc+'</p>');
}
var $content = $('.cards-in-grid');
var url = 'link-for private use now';
$.get(url, function (response) {
var output = '';
console.log(response);
$.each(response, function (k, item) {
title = item.title;
var author = item.img;
desc = item.desc;
output += '<li><img src="'+author+'" alt=""><h2>' + title + '</h2></li>';
$(".cards-in-grid ul").on("click", "li", function(){
newWin;
});
return k;
});
$content.html(output);
});
});
`
$(function () {
var $content = $('.cards-in-grid');
var url = 'link-for private use now';
$.get(url, function (response) {
var output = '';
var list = "li";
$.each(response, function (k, item) {
var listNum = list+k;
var idy = "#"+listNum;
var desc = "";
title = item.title;
var author = item.img;
desc = item.desc;
//GIVE ID to each LI using a variable
output += '<li id="'+listNum+'"><img src="'+author+'" alt=""><h2>' +
title + '</h2></li>';
$content.html(output);
$content.on("click",idy, function(){
var w = window.open();
$(w.document.body).html('<p>'+desc+'</p>');
});
return k;
});
});
});
This worked perfectly, some thinking and pondering and was able to make it work!!
Kindly Upvote the answer, if it helped you! Thanks!
I am trying to generate a table of data from a JSON file using Javascript but am having difficulty because of the bean:write tag. The bean: is getting removed, so only <write name="offenderCountVO" property="addressCount"/> seems to be getting parsed. Is this approach even feasible?
From the page that generates the table:
// Build profile section from JSON file
$.getJSON('<%=request.getContextPath()%>/jsp/json/offenderProfileJSON.jsp', function(data) {
//alert('loading JSON');
var items = [];
var table = $('<table class="profile"><\/table>');
var profileCols = 2;
var td = "";
// Build array of profile categories
for (i = 0; i < data.length; i++) {
//alert("building items");
// Check if this category can be displayed in this module
var item = data[i];
var modules = item["modules"];
//alert("Start check");
if (modules.indexOf(appName) > 0) {
// This category should be displayed
//alert ("Passed");
var label = item["label"];
var link = item["link"];
var name = item["name"];
var property = item["property"];
newCategory = { label: label, modules: modules, link: link, name: name, property: property };
items.push(newCategory);
}
}
// Alphabetically sort categories by label
//alert(items.length);
for (i = 0; i < items.length; i++) {
html = '<tr><td><a href="<%=request.getContextPath()%>/' + items[i].link + '">'
+ items[i].label + '</a></td><td>\u003Cbean\u003Awrite name="'
+ items[i].name + '" property="' + items[i].property + '" /\u003E</td></tr>';
}
$("#testArea").html(html);
//table.appendTo("#testArea");
alert("Done");
}).error(function() {
$("#testArea").html('<span class="error">Error parsing JSON.</span>');
});
The JSON file:
[
{
"label" : "Address",
"modules" : "AGNT,BOOKING,DIO,OMP,OTA",
"link" : "offenderAddress.do?method=list",
"name" : "offenderCountVO",
"property" : "addressCount"
},
{
"label" : "Assessments",
"modules" : "AGNT,BOPP,OMP,OTA",
"link" : "offenderAssessmentList.do?method=list",
"name" : "offenderCountVO",
"property" : "assessmentCount"
}
]
I hope I've explained the issue well enough -- I'm working on several different projects and my head is spinning right now, so let me know if you need any clarification. Any guidance would be appreciated.
<bean:write> is a tag understood by JSP on the server-side, at the point when the initial page is created.
Using:
'<td>\u003Cbean\u003Awrite name="'+ items[i].name + '" property="' + items[i].property + '" /\u003E</td>'
from JavaScript makes no sense because the web browser that includes the resultant <bean:write> tag in its page DOM doesn't know anything about Java or bean tags. When the browser's HTML parser sees <bean:write> it thinks only "that's some write tag that I don't know about, spelled funny" and not "I had better ask the server-side what it's value for the property of that bean is".
If you want the browser to see the server-side value of a variable, you must return that value itself in the JSON response to the browser, not just a name and value pair that only mean anything to the bean-based server side.
Note also that dropping unescaped strings into HTML markup is dangerous. Without HTML-escaping, you have cross-site-scripting security holes when any of the item values may contain user-submitted values. Use DOM-property methods to set element text and attribute values instead of trying to create HTML markup strings from JavaScript. eg:
<input type="hidden" id="contextPath" value="<c:out value="${pageContext.request.contextPath}"/>"/>
...
var cp = document.getElementById('contextPath').value;
for (var i= 0; i<items.length; i++) {
table.append(
$('<tr>').append(
$('<td>').append(
$('<a>', {href: cp+'/'+items[i].link, text: items[i].label})
)
).append(
$('<td>', {text: items[i].value_of_whichever_property_it_is})
)
);
}
I'm trying to display particular json data in a form of Bullets. Each chapter data into <li>, each title into <p> and make those titles as a link. Finally, consider to the index of clicked title display related content in a second <div>. I have already some piece of code below (not working yet).
Html:
<div id="page1">
<ul id="courses"></ul>
</div>
<div id="page2">
<p id="content"></p>
</div>
JS code:
var jsonString = '[{"chapter":"General","title":"News forum","content":"Text1"},
{"chapter":"CHAPTER 1","title":"1.1 Introduction","content":"Text2"},
{"chapter":"CHAPTER 1","title":"1.2 Main Idea","content":"Text3"},
{"chapter":"CHAPTER 2","title":"2.1 Architecture","content":"Text4"},
{"chapter":"CHAPTER 3","title":"3.1 Liter.overview","content":"Text5"}]';
var myData = JSON.parse(jsonString);
$(document).ready(function() {
var $clist = $('#courses');
for(var i in myData) {
$('<li><h3>' +this.[i].chapter+ '</h3><p>' +this.title+ '</p></li>').appendTo($clist);
}
function dContent() {
var $ccontent = $('#content');
$(this.[i].content).appendTo($ccontent);
}
});
Expected result:
- General
News forum // onclick display 'Text1' in <p id="content">
- CHAPTER 1
1.1 Introduction // onclick display 'Text2' in <p id="content">
1.2 Main Idea // onclick display 'Text3' in <p id="content">
- CHAPTER 2
2.1 Architecture // onclick display 'Text4' in <p id="content">
- CHAPTER 3
3.1 Liter.overview // onclick display 'Text5' in <p id="content">
Any help would be appreciated.
UPDATE: Here is the JSFIDDLE project.
var jsonString = '[{"chapter":"General","title":"News forum","content":"Text1"},{"chapter":"CHAPTER 1","title":"1.1 Introduction","content":"Text2"},{"chapter":"CHAPTER 1","title":"1.2 Main Idea","content":"Text3"},{"chapter":"CHAPTER 2","title":"2.1 Architecture","content":"Text4"},{"chapter":"CHAPTER 3","title":"3.1 Liter.overview","content":"Text5"}]';
var myData = JSON.parse(jsonString);
var dContent = function(event) {
$ccontent.html($(this).data('content'));
}
var $clist = $('#courses');
var $ccontent = $("#content");
var html = '';
var chapterList = [];
$clist.on('click', 'li', dContent);
$.each(myData, function(index, item) {
if ($.inArray(item.chapter, chapterList) === -1) {
chapterList.push(item.chapter);
html += '<li data-content="'+ item.content +'"><h3>' + item.chapter + '</h3><p>' + item.title + '</p></li>';
}
else {
html += '<li data-content="'+ item.content +'"><p>' + item.title + '</p></li>'
}
});
$clist.html(html);
I've written a script to do this, including putting items from the same chapter together. You can see a demo fiddle here.
I used native JavaScript for most of it, with the exception of jQuery for the $(a).on('click', .. and $(document).ready to ensure compatibility. Why is it so long? Because I built the <ul> with DOM methods, instead of a html string. This made it easy to cache and append elements. Finally, the content is added via a generator function. The way I did it means the page will use slightly more memory but you can have any string that is valid in JavaScript displayed in the content section. You may want to style it with whitespace: pre-wrap; to display new lines as expected.
Anyway, here is the code
var jsonString = '[{"chapter":"General","title":"News forum","content":"Text1"},\
{"chapter":"CHAPTER 1","title":"1.1 Introduction","content":"Text2"},\
{"chapter":"CHAPTER 1","title":"1.2 Main Idea","content":"Text3"},\
{"chapter":"CHAPTER 2","title":"2.1 Architecture","content":"Text4"},\
{"chapter":"CHAPTER 3","title":"3.1 Liter.overview","content":"Text5"}]';
// the \ at line ends is to escape the new line in the string literal
var myData = JSON.parse(jsonString);
$(document).ready(function() {
var courses_ul = document.getElementById('courses'), // cache elements
content_elm = document.getElementById('content'),
i, li, h3, p, a, // vars for loop
chapters = {}, chap; // cache chapters
for (i = 0; i < myData.length; ++i) {
chap = myData[i].chapter; // shorthand since we'll use it a few times
// make <p>, <a>
p = document.createElement('p');
a = document.createElement('a'); // could append <a> to <p> here if you want
a.setAttribute('href', '#page2');
a.appendChild(document.createTextNode(myData[i].title));
// set up click
$(a).on('click', (function (content) { // generator - will give scope to
return function () { // this returned event listener.
content_elm.innerHTML = '';
content_elm.appendChild(document.createTextNode(content));
};
}(myData[i].content))); // chose `content` not `i` so no reliance on `myData`
// now check cache if chapter exists -
if (chap in chapters) { // retreive <li> for chapter from cache
li = chapters[chap]; // from cache
// append <p>, <a>
li.appendChild(p).appendChild(a);
} else { // if not in cache
li = document.createElement('li'); // make a new <li>
chapters[chap] = li; // and cache
// make & append <h3>
h3 = document.createElement('h3');
h3.appendChild(document.createTextNode(chap));
li.appendChild(h3);
// append <p>, <a> and to <ul>
courses_ul.appendChild(li).appendChild(p).appendChild(a);
}
}
});
You have an invalid JSON structure. The correct structure is below:
[
{
"chapter": "General",
"title": "News forum",
"content": "Text1"
},
{
"chapter": "CHAPTER 1",
"title": "1.1 Introduction",
"content": "Text2"
},
{
"chapter": "CHAPTER 1",
"title": "1.2 Main Idea",
"content": "Text3"
},
{
"chapter": "CHAPTER 2",
"title": "2.1 Architecture",
"content": "Text4"
},
{
"chapter": "CHAPTER 3",
"title": "3.1 Liter.overview",
"content": "Text5"
}
]
Note that comma here 3.1 Liter.overview","content":"Text5"}, in your JSON structure, it fails here
UPDATED ANSWER WITH CODE
var jsonString = '[{"chapter": "General","title": "News forum","content": "Text1"},{"chapter": "CHAPTER 1","title": "1.1 Introduction","content": "Text2"},{"chapter": "CHAPTER 1","title": "1.2 Main Idea", "content": "Text3"},{"chapter": "CHAPTER 2","title": "2.1 Architecture","content": "Text4"},{"chapter": "CHAPTER 3","title": "3.1 Liter.overview","content": "Text5"}]';
var myData = JSON.parse(jsonString);
$(document).ready(function() {
function dContent() {
$("#content").css("border","2px solid red").css("height","100px");
$("#content").html($(this).data('value'));
}
$("#courses").on('click','li', dContent)
$.each(myData, function(index,item) {
$("#courses").append("<li class='li' data-value="+item.content+">"+item.chapter+" <p>"+item.title+"</p></li>");
})
});
DEMO ON JSFIDDLE
this.[i].chapter should probably be myData[i].chapter. As it is, it's a syntax error.
Then you should rethink whether your other uses of this are correct.
Copying this into your JSFiddle and checking in jQuery as well, will make it work.
var jsonString = '[{"chapter":"General","title":"News forum","content":"Text1"},{"chapter":"CHAPTER 1","title":"1.1 Introduction","content":"Text2"},{"chapter":"CHAPTER 1","title":"1.2 Main Idea","content":"Text3"},{"chapter":"CHAPTER 2","title":"2.1 Architecture","content":"Text4"},{"chapter":"CHAPTER 3","title":"3.1 Liter.overview","content":"Text5"}]';
var myData = JSON.parse(jsonString);
$(document).ready(function() {
var $clist = $('#courses');
$.each(myData, function(i,o){
$('<li><h3>' +o.chapter+ '</h3><p>' +
'<a href="#page2" onclick="dContent(\''+o.content+'\')">' +
o.title + '</a></p></li>').appendTo($clist);
});
window.dContent = function(content) {
var $ccontent = $('#content');
$ccontent.append(content);
}
});
I need to find a way to use javascript to make multiple links for my left nav. I will have seperators dividing the links into categories.
This is my current code.
links = new Array();
links[1]="<span class='asep' style='border-top: 0px; margin-top: 0px;'>Welcome</span>";
links[2]="<a href='#'>Home</a>";
links[3]="<span class='asep'>Body Jewelry</span>";
links[4]="<a href='#'>Circular Barbells</a>";
links[5]="<a href='#'>Belly Button</a>";
links[6]="<a href='#'>Curved Barbells</a>";
links[7]="<span class='asep'>User Controls</span>";
links[8]="<a href='#' onclick='window.print(); return false'>Print This Page</a>";
function writeLinks() {
document.getElementById('nav1').innerHTML = links[1] + links[2] + links[3] + links[4] + links[5] + links[6] + links[7] + links[8];
document.getElementById('featured').innerHTML = ' <b>Featured Product</b><br><img src="icon1.gif" border="0"><br>Product Title';
}
setTimeout(writeLinks, 0); // Fires the function on page load without stopping other loads
Is there an easier way to do this?
There are various aspects of your methods which can be made "easier":
links = new Array();
Can be better-written as links = [];. (almost) everything you'll come across in Javascript is already an object, so being verbose about it doesn't add clarity.
links[1]="first..."
links[2]="second...";
can be better-written using .push(), so that you don't need to specify each index, eg:
links.push("first");
links.push("second");
or, if you're doing it all at once, using an array-literal, eg:
links = [
"first",
"second"
];
less-nice, in my opinion, but also an option, could be a mixture of both, using .concat():
links = [
"first",
"second"
];
links = links.concat([
"third",
"fourth"
]);
It might make sense to group things together using an array of bare objects, too:
sections = [
{
heading: '<span class="asep">First section...</span>',
links: [
'First',
'Second'
]
},
{
heading: '<span class="asep">Second section...</span>',
links: [
'Third',
'Fourth'
]
},
];
function writeLinks(){
var html = "";
for( var i = 0; i < sections.length; i++ ){
var section = sections[i];
html += section.heading + section.links.join("");
}
document.getElementById('nav1').innerHTML = html;
}
setTimeout(writeLinks, 0);
Note also the use of .join("") to join all elements of an array together as strings.
Next, you've got a lot of duplication in your code. You could specify only the parts which are different, eg:
sections = [
{
heading: "First section...",
links: [
"First",
"Second"
]
},
/* ...snip... */
];
function writeLinks(){
var html = "";
for( var i = 0; i < sections.length; i++ ){
var section = sections[i];
html += '<span class="asep">' + section.heading + "</span>";
for( var j = 0; j < section.links.length; j++ ){
html += '' + section.links[j] + "";
}
}
document.getElementById('nav1').innerHTML = html;
}
setTimeout(writeLinks, 0);
You could get rid of some of that raw HTML and simplify some of the loops, etc, by using a common library, such as jQuery or Prototype. This would also allow you to actually check that the document is ready for you to operate on it, rather than using that fragile setTimeout() hack. eg:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
/* ...snip... */
$(function(){
var nav = $("<div />").attr("id", "nav1");
$.each(sections, function(i,section){
nav.append( $("<span />").addClass("asep").text(section.heading) );
$.each(section.links, function(i,link){
nav.append( $("<a />").attr("href", "#").text(link) );
}
}
$("#nav1").replaceWith( nav );
});
</script>
All of those may be considered "easier" depending on your mood.
var arr = [];
arr[0] = <span class='asep'>Body Jewelry</span>;
arr[1] = <span class='asep'>Do Something</span>;
function writeLinks(){
document.getElementById("nav1").innerHTML = arr.join("");
}
Array.Join is faster than concat operation .
This might be a bit overkill, but you might want to look at a client side framework that supports models and templates, such as backbone.js. Then you could store all your links in a model which can easily be changed (and will automatically update the view for you through events), and you can also use underscore.js templates so you don't have to write any html as a string literal.
I tried this with xml, but the behavior was odd from firefox to IE.
I haven't worked with json before, so any help would be appreciated.
here's my json:
{
"storeList":{
"state":[
{
"stateName":"Maine",
"store":[
{
"storeName":"Store 1",
"storeID":"store1",
"storeURL":"http:\/\/www.sitename.com"
},
{
"storeName":"Store 2",
"storeID":"store2",
"storeURL":"http:\/\/www.sitename.com"
},
{
"storeName":"Store 3",
"storeID":"store3",
"storeURL":"http:\/\/www.sitename.com"
}
]
},
{
"stateName":"Connecticut",
"store":[
{
"storeName":"Store 1",
"storeID":"store1",
"storeURL":"http:\/\/www.sitename.com"
}
]
}
]
}
}
and the structure I'm going for -
<div id="storeList">
<ul>
<li>
<h3>State Name 1</h3>
storename
storename
</li>
<li>
<h3>State Name 2</h3>
storename
</li>
</ul>
</div>
update
tried a solution below, loading the json from an external file, but I get an error that object is not defined:
$(document).ready(function() {
var object;
$.getJSON('xml/storeList.json', function(json) {
object = json;
});
$('#storeList').append('<ul/>')
$.each(object.storeList.state, function() {
var list = $('#storeList ul'),
listItem = $('<li/>'),
html = listItem.append($('<h3/>').text(this.stateName));
$.each(this.store, function() {
listItem.append($('<a />').attr('href', this.storeURL).text(this.storeName));
});
list.append(html)
});
});
I would use a template engine. With a template engine you can define your template (which is easy to read and maintain) like that:
<script id="template" type="text/x-jquery-tmpl">
<ul>
{{#each state}}
<li>
<h3>{{=stateName}}</h3>
{{#each store}}
{{=storeName}}
{{/each}}
</li>
{{/each}}
</ul>
</script>
and then simply call
$("#storeList").html(
$("#template").render(json.storeList)
);
to fill your div
<div id="storeList"></div>
I have a demo ready. The template engine I use here is JsRender.
Here's a simple example:
$('#storeList').append('<ul/>')
$.each(object.storeList.state, function() {
var list = $('#storeList ul'),
listItem = $('<li/>'),
html = listItem.append($('<h3/>').text(this.stateName));
$.each(this.store, function() {
listItem.append($('<a />').attr('href', this.storeURL).text(this.storeName));
});
list.append(html)
});
Example
EDIT
var object;
$.getJSON('xml/storeList.json', function(json) {
object = json;
$('#storeList').append('<ul/>')
$.each(object.storeList.state, function() {
var list = $('#storeList ul'),
listItem = $('<li/>'),
html = listItem.append($('<h3/>').text(this.stateName));
$.each(this.store, function() {
listItem.append($('<a />').attr('href', this.storeURL).text(this.storeName));
});
list.append(html)
});
});
JSON is nothing but a subset of Javascript object literal notation that allows nested objects and/or arrays, so you will want to study up on the Javascript object and array data structures.
That being said, once your "bare" json is assigned to a variable, let's assume "json" (test by prepending with "json=") you can probably begin to work with your JSON in the following manner, just as you would with an array:
for (var i=0, n=json.storeList.state.length; i<n; i++) {
var state = json.storeList.state[i];
console.log(state.stateName); //Maine, then Connecticut
for (var j=0, k=state.store.length; j<k; j++) {
var store = state.store[j]; //the object containing store name, id & URL
console.log(store.storeID);
}
}
PS....my answer is "pure" Javascript as opposed to using jQuery, so if you're committed to doing things the jQuery way, definitely consider the other answers. But it's good to get familiar with the Javascript foundation behind the various frameworks such as jQuery, ExtJS, etcetera, in case you ever have to switch.
Use jQuery's $.each() function to iterate over object properties, and just a standard for loop for iterating over the arrays.
Here's a working example: http://jsfiddle.net/qZ6U4/
And the code:
var htmlStr = '';
$.each(myObj, function(i,v){
htmlStr += '<div id="' + i + '">';
$.each(v, function(i, v){
htmlStr += '<ul>';
for(var i = 0; i < v.length; i++){
htmlStr += '<li><h3>' + v[i].stateName + '</h3>';
for(var n = 0; n < v[i].store.length; n++){
var store = v[i].store[n];
htmlStr += '' + store.storeName + '';
}
htmlStr += '</li>';
}
htmlStr += '</ul>';
});
htmlStr += '</div>';
});