I am a newbie with json arrays/objects. I am trying to get to some subobjects within my .json file. I have tried the suggestions on here, but I keep getting "undefined" results. Here is the .json --
{
"DACcourses": [
{
"longTitle": "<a href='#'>Ammo-29 Electrical Explosives Safety for Naval Facilities</a>",
"longDescript": "ammo-29.html",
"atrrsLink": "Win 95+",
"delMeth": "standard",
"sked": [
{
"classNumb": "926",
"startDate": "4/16/2012",
"endDate": "4/20/2012",
"location": "NMC Fort Worth, TX",
"status": "scheduled",
"emptySeats": "Availability"
},
{
"classNumb": "001",
"startDate": "6/4/2012",
"endDate": "6/8/2012",
"location": "McAlester, OK",
"status": "scheduled",
"emptySeats": "Availability"
},
{
"classNumb": "920",
"startDate": "6/18/2012",
"endDate": "6/22/2012",
"location": "Belle Chasse, LA",
"status": "scheduled",
"emptySeats": "Class Full"
}
]}
]}
I must be doing something fundamentally wrong. so here is my code. In the end I am trying to build table rows out of each of the 'sked' objects. But I am having problems with getting individual data elements to show in the console. Here has been my attempts:
$('#content').on("click", "#catList tbody tr", function() {
var aData = oTable.fnGetData( this );
console.log( aData );
var scheduleData = aData.sked;
var catLink = 'catalog/' + aData.longDescript;
$('#fullDescript').load(catLink, function() {
if (!$('#fullDescript #offerings')) {
$('.enrollBTN').hide();
};
if ($(scheduleData).length > 0) {
$(scheduleData).each(function() {
for(var i = 0; i < scheduleData.length; i++) {
/*var startDate = aData.sked.startDate[2];
var endDate = aData.sked.endDate[3];
var location = aData.sked.location[4];
var classNumb = aData.sked.classNumb[1];
var status = aData.sked.status[5];
var emptySeats = aData.sked.emptySeats[6];*/
//var item = scheduleData[i];
console.log( aData.sked.startDate[2] );
var html = "<tr>";
html += "<td>" + item.classNumb + "<\/td>";
//console.log( aData.sked[1].classNumb );
/*html += "<td>" + scheduleData.endDate + "<\/td>";
html += "<td>" + scheduleData.location + "<\/td>";
html += "<td>" + scheduleData.classNumb + "<\/td>";
html += "<td>" + scheduleData.status + "<\/td>";
html += "<td>" + scheduleData.emptySeats + "<\/td>";*/
html += "<\/tr>";
//return scheduleData;
};
$('#schedule tbody').append($(html));
});
};
});
$('#content').hide();
$('#fullDescript').show();
});
Any help is appreciated.
It seems like you would only need the each or for loop, but not both. It also looks like there's some confusion in there on whether to use item = scheduleData[i] or not. Try this:
if ($(scheduleData).length > 0) {
for(var i = 0; i < scheduleData.length; i++) {
var item = scheduleData[i];
var html = "<tr>";
html += "<td>" + item.endDate + "</td>";
// ... etc
html += "</td>";
}
}
Just as a PS, I'd recommend looking into a JS templating tool like Mustache.js. This would allow you to separate data from display template, so you could eliminate the parsing code. It would look something like this:
var template = "{{#sked}}<tr><td>{{endDate}}</td><td>{{location}}</td></tr>{{/sked}}";
var html = "<table>" + Mustache.render(template, aData) + "</table>";
I must be doing something fundamentally wrong
Yes you are.
When you use .each loop, you refer to the current element by this keyword. So you do not need the for loop. Or, if you want the for loop, you do not need the .each loop. In my opinion, use the for loop. .each is just an overhead in this case.
UPDATE: #dbaseman gave you exactly what you need :)
UPDATE 2: Please try the following code. Basically its same as that of dbaseman, but dbaseman's snippet missed closing the <tr> element.
if ($(scheduleData).length > 0) {
for(var i = 0; i < scheduleData.length; i++) {
var item = scheduleData[i];
var html = "<tr>";
html += "<td>" + item.endDate + "</td>";
// ... etc
html += "</tr>"; // should close the <tr> here
}
}
Related
I have JSON data like this:
[0:{name:"jason",height:"150cm"},
1:{name:"henry",height:"178cm"}]
I'm trying to do a for loop in my function, which is
function DrawTable(output) {
var general = output;
var sb = new StringBuilder();
for (var i = 0; i < *total row in the json*; i++)
sb.append("<td>" + general[0][i]["name"] + "</td>");
sb.append("<td>" + general[0][i]["height"] + "</td>");
}
I don't know the way to do it..
First off: that data isn't JSON.
For the sake of argument, let's pretend it was formatted as such:
[{
"name": "jason",
"height": "150cm"
}, {
"name": "henry",
"height": "178cm"
}]
Which would be valid JSON.
You could then do something more like this:
If using jQuery:
function DrawTable(jsonString) {
var stuff = JSON.parse(jsonString);
var table = createElement('table')
.append(
createElement('thead')
.append(
createElement('tr')
.append(
createElement('th').text('Name'),
createElement('th').text('Height')
)
)
);
var body = createElement('tbody');
stuff.forEach(function(item) {
body
.append(
createElement('tr')
.append(
createElement('td').text(item.name),
createElement('td').text(item.height)
)
);
});
//append body to table and show on page somewhere
}
Or, based on your existing code:
function DrawTable(output) {
var general = JSON.parse(output);
var sb = new StringBuilder();
for (var i = 0; i < general.length; i++) {
sb.append("<td>" + general[i].name + "</td>");
sb.append("<td>" + general[i].height + "</td>");
}
}
If your data happens to be formatted like:
{
0: {name:"jason",height:"150cm"},
1: {name:"henry",height:"178cm"}
}
instead of wrapped in an array. Then looping through Objects.values(yourData) might be what you are looking for:
function DrawTable(objectsData) {
var htmlString = '';
Object.values(objectsData).forEach((object) => {
htmlString += "<td>" + object.name + "</td>";
htmlString += "<td>" + object.height + "</td>";
});
return htmlString;
}
This question already has answers here:
Sort array of objects by string property value
(57 answers)
Closed 7 years ago.
Basically all I want is to sort this array based on each item that is shown below, with the exception of the "Action' and 'Thumb Image' ones. So the way I have it set up is that the header for each of rows is a link, and when that link is clicked the list will be sorted based on what was clicked. So for example, if Title is clicked, then I want to have a "titleSort()" function that will sort based on title. I have no idea how to accomplish this, so any help is much appreciated. I was hoping that VideoList.sort(Title) would work, for example.
Thanks,
JS
for(var i = 0; i<VideoList.length; i++) {
content += "<tr>";
content += "<td width='20%'><a href='https://www.youtube.com/watch?v=" + VideoList[i].VideoID + "'onclick='playVideo("+i+")'>" + "<img src ='https://i.ytimg.com/vi/" + VideoList[i].VideoID + "/hqdefault.jpg' width=175 height=130></a></td>";
content += "<td>" + VideoList[i].Title + "</td>";
content += "<td>" + VideoList[i].VideoID + "</td>";
content += "<td>" + VideoList[i].DateUploaded + "</td>";
content += "<td>" + VideoList[i].Category+ "</td>";
content += "<td>" + VideoList[i].Time+ "</td>";
content += "<td width='20%'>" + VideoList[i].Action + "</td>";
content += "</tr>";
You can use sort to sort VideoList according to title this code may work for you
VideoList.sort(function(a,b){
return a.Title > b.Title;
});
I agree with #manishrw about lodash. AND any number of libraries would make this easier - like jQuery and Angular. There are a ton of table-specific libraries out there that have sort function built in. However, I built it to show how you could do it, including re-building the table once it's sorted. To do that I had to create the array with mock data. Here's a jsfiddle:
https://jsfiddle.net/mckinleymedia/c02nqdbz/
And here's the code:
<div id="target"></div>
<script>
var VideoList = [],
content,
fields = ["Title", "VideoID", "DateUploaded", "Category", "Time", "Action"],
num = 10,
sortField = "Title",
sortDirection = 1,
compare = function(a, b) {
if (a[sortField] < b[sortField]) return -1 * sortDirection;
if (a[sortField] > b[sortField]) return 1 * sortDirection;
return 0;
},
sortArray = function(field) {
if( sortField === field ) sortDirection = -1 * sortDirection;
sortField = field;
VideoList.sort(compare);
buildTable();
},
creatVideos = function() {
for (var x = 0; x < num; x++) {
var video = {},
z = Math.floor(Math.random() * 200);
for (var i in fields) {
if(fields[i]==='VideoID') {
video[fields[i]] = z;
} else {
video[fields[i]] = fields[i] + "-" + z;
}
}
VideoList.push(video);
}
},
buildTable = function() {
content = "<table>";
content += "<tr>";
content += "<th>image</th>";
for (var x in fields) {
content += "<th class='field field-" + fields[x] + "' onclick='sortArray(\"" + fields[x] + "\")'>" + fields[x] + "</th>";
}
content += "</tr>";
for (var i in VideoList) {
content += "<tr>";
content += "<td width='20%'><a href='https://www.youtube.com/watch?v=" + VideoList[i].VideoID + "'onclick='playVideo(" + i + ")'>" + "<img src ='https://i.ytimg.com/vi/" + VideoList[i].VideoID + "/hqdefault.jpg' width=175 height=130></a></td>";
for (var x in fields) {
content += "<td>" + VideoList[i][fields[x]] + "</td>";
}
content += "</tr>";
}
content += "</table>";
document.getElementById('target').innerHTML = content;
};
creatVideos();
buildTable();
</script>
Here's a generic function for you
function sortBy(list, field) {
return list.sort(function(a,b) {
return a[field] < b[field];
});
}
sortBy(VideoList, 'Title');
Warning: sortBy will mutate the list input
You could also make it take a comparator so you control the 'direction' of the sort
// you you need to return -1, 0, or 1 for the sort to work reliably
// thanks, #torazaburo
function compareAsc(a,b) {
if (a < b) return -1;
else if (a > b) return 1;
else return 0;
}
function compareDesc(a,b) {
return compareAsc(a,b) * -1;
}
function sortBy(list, field, comparator) {
return list.sort(function(a,b) {
if (comparator instanceof Function)
return comparator(a[field], b[field]);
else
return compareAsc(a[field], b[field]);
});
}
// default sort ascending
sortBy(VideoList, 'Title');
// sort descending
sortBy(VideoList, 'Title', compareDesc);
Use Lodash library. It's easy to use and efficient in run-time. It has a function sortBy, which can be used to sort a collection based on they key you provide.
P.S. Lodash is my goto Library for any operation to be performed on any collection.
EDITED:
I'm (still) having a little trouble getting values from a nested array in JSON and appending them to generated html.
I'm currently using the following JSON (updated):
{
"OuterArray": [
{
"memberId": "01",
"key01": "",
"included": "true",
"nestedArray": [
{ "keyA": "", "keyB": "" },
{ "keyA": "", "keyB": "" }
]
},
{
"memberId": "02",
"key01": "",
"included": "true",
"nestedArray": [
{ "keyA": "", "keyB": "" },
{ "keyA": "", "keyB": "" }
]
},
{
"memberId": "03",
"key01": "",
"included": "false",
"nestedArray": [
{ "keyA": "", "keyB": "" },
{ "keyA": "", "keyB": "" }
]
},
{
"memberId": "04",
"key01": "",
"included": "true",
"nestedArray": [
{ "keyA": "", "keyB": "" },
{ "keyA": "", "keyB": "" }
]
}
]
}
And this js:
for (var i = 0; i < outerArray.length; i++) {
if (outerArray[i].included !== "false") {
var key01 = outerArray[i].key01;
var key02 = outerArray[i].key02;
// etc.
var nestedArray = outerArray[i]["nestedArray"];
myDiv.innerHTML +=
"<div class=\"outer-array-stuff\">"
+ "<p class=\"key01\">" + key01 + "</p>"
+ "<p class=\"key02\">" + key02 + "</p>"
+ "<div class=\"nested-array-stuff\">" // help?
+ "</div>"
+ "</div>"
var nestedArrayStuff = document.getElementsByClassName("nested-array-stuff")[i];
for (var j=0; j<outerArray.length; j++) {
nestedArrayStuff.innerHTML += "<p class=\"keyA\">" + nestedArray[j].keyA + "</p>";
}
}
Note that one of the keys in the outer array has a boolean value which determines whether or not it (the outer array member) is - and its nested array stuff are - included in the page.
So just to reiterate, the goal is:
<div class="outer-array-stuff">
<!-- <snip: some outer array key/values here /> -->
<div class="nested-array-stuff">
<div class="nested-array-stuff">
<p>[e.g., nested array key 1 value]</p>
<p>[e.g., nested array key 2 value]</p>
<p>[etc.]</p>
</div>
</div>
If all the outer array members 'included' are 'true', everything outer & nested loads, but this is not exactly what I want; I need to filter so that only those 'included' !== "false". So now my problem is that despite being inside the if 'included'/else loop, the outer array members stop loading at the first excluded outer array member (actually, the next 'true' outer array member does load, but its nested array stuff doesn't, and then nothing further loads, the entire outer array loop dies.
Any insight as to why this is happening?
Many thanks to dreyescat for the help to this point.
P.S. generally I'm trying to minimize my reliance on jQuery.
Many thanks, svs
You are almost there. Here is your code revised with some comments.
// Generally is not a good practice iterate arrays using for..in
//for (var i in outerArray) {
for (var i = 0; i < outerArray.length; i++) {
var key01 = outerArray[i].key01;
var key02 = outerArray[i].key02;
// This should by outerArray array and not jsonData object.
var nestedArray = outerArray[i]["nestedArray"];
myDiv.innerHTML +=
"<div class=\"outer-array-stuff\">"
+ "<p class=\"key01\">" + key01 + "</p>"
+ "<p class=\"key02\">" + key02 + "</p>"
+ "<div class=\"nested-array-stuff\">" // help?
+ "</div>"
+ "</div>"
// getElementsByClassName gets a list of elements that have that class.
// I suppose you want to add the elements to the corresponding outer array.
// Let's use the loop index i to get the proper parent element. You could also
// just get the last one.
var nestedArrayStuff = document.getElementsByClassName("nested-array-stuff")[i]; // help?
// Again I recommend you not to use for..in for arrays.
for (var obj in nestedArray) {
nestedArrayStuff.innerHTML += "<p class=\"keyA\">" + nestedArray[obj].keyA + "</p>"; // NOPE
}
}
See demo.
You could also build the entire nested array stuff before adding it to the div element. Then you don't need to query the document to get the nested array stuff element.
for (var i in outerArray) {
var key01 = outerArray[i].key01;
var key02 = outerArray[i].key02;
var nestedArray = outerArray[i]["nestedArray"];
var nestedArrayStuff = '<div class=\"nested-array-stuff\">';
for (var obj in nestedArray) {
nestedArrayStuff += "<p class=\"keyA\">" + nestedArray[obj].keyA + "</p>"; // NOPE
}
nestedArrayStuff += '</div>';
myDiv.innerHTML += "<div class=\"outer-array-stuff\">"
+ "<p class=\"key01\">" + key01 + "</p>"
+ "<p class=\"key02\">" + key02 + "</p>"
+ nestedArrayStuff
+ "</div>"
+ "</div>";
}
See demo
nestedArray is not a string. your nestedArray array loop should be as follows.
var nestedArray = outerArray[i].nestedArray;
for (var j in nestedArray) {
console.log(nestedArray[j].keyA);
console.log(nestedArray[j].keyB);
}
Here is your complete solution, I used lists to output content. It assumes we have one container:
<div id="mydiv"></div>
Than JS would be:
var myDiv = document.getElementById('mydiv');
var outerArray = [
{
"memberId":"01",
"key01":"",
"key02":"key02 exists, ...",
"included":"true",
"nestedArray":[
{
"keyA":"1",
"keyB":"2"
},
{
"keyA":"3",
"keyB":"4"
}
]
},
{
"memberId":"02",
"key01":"key01 value..",
"included":"true",
"nestedArray":[
{
"keyA":"5",
"keyB":""
},
{
"keyA":"",
"keyB":"8"
}
]
},
{
"memberId":"03",
"key02":"",
"included":"false",
"nestedArray":[
{
"keyA":"",
"keyB":"9"
},
{
"keyA":"",
"keyB":""
}
]
},
{
"memberId":"04",
"key01":"value of key01",
"key02":"key02 value ...",
"included":"true",
"nestedArray":[
{
"keyA":"",
"keyB":"10"
},
{
"keyA":"11",
"keyB":"12"
}
]
}
];
var insertHtml = '';
for (var i = 0; i < outerArray.length; i++) {
if (outerArray[i].included !== "false") {
insertHtml += "<ul class=\"outer-array-stuff\">";
insertHtml += " <li>";
insertHtml += " <p class=\"memberId\">memberId(" + i + "): " + outerArray[i].memberId + "</p>"
insertHtml += " <p class=\"key01\">key01: " + ( ( typeof outerArray[i].key01!='undefined' && outerArray[i].key01 ) ? outerArray[i].key01 : '') + "</p>"
insertHtml += " <p class=\"key02\">key02: " + ( ( typeof outerArray[i].key02!='undefined' && outerArray[i].key02 ) ? outerArray[i].key02 : '') + "</p>"
var nestedArray = outerArray[i]["nestedArray"];
if ( nestedArray.length>0 ) {
insertHtml += " <ul class=\"nested-array-stuff\">"
for (var j=0; j<nestedArray.length; j++) {
insertHtml += "<li class=\"keyA\">keyA(" + j + "): " + nestedArray[j].keyA + "</li>";
insertHtml += "<li class=\"keyB\">keyB(" + j + "): " + nestedArray[j].keyB + "</li>";
};
insertHtml += " </ul>"
};
insertHtml += " </li>";
insertHtml += "</ul>"
}
}
myDiv.innerHTML = insertHtml;
I am interfacing with an API which returns JSON data to me. As the results are not stored in a file, but rather server memory, I am having a hard time figuring out how to access the data and write it to my html webpage. Here's what my $.ajax call looks like:
$.ajax({
type: "post",
url:"https://www.xxx/v1/trips/search? key=xxxx",
data:JSON.stringify({request : requestTrav1Dest1}),
dataType:"json",
success:successFunction,
headers:{"Content-Type":"application/json"}
});
Here's what the JSON I get back from the server looks like:
{
"kind": "#tripsSearch",
"trips": {
"kind": "#tripOptions",
"tripOption": [
{
"saleTotal": "USD294.10",
"id": "DMfSXrkVQGKTVQsDD5l60N004",
},
"saleTotal": "USD333.10",
"id": "DMfSXrkVQGKTVQsDD5l60N002",
},
{
"saleTotal": "USD225.94",
"id": "DMfSXrkVQGKTVQsDD5l60N005",
}
]
}
}
What I really need is the saleTotal for each tripOption.
I broke out the function that runs if the query is a success here:
function successFunction(servResponse){
$('#content').load('resultsPage.html #content');
var newContent = '';
for(var i = 0; i < servResponse.trips.tripOption[i].length; i++){
newContent += '<div class="results">';
newContent += '<p>' + "Option " + (i+1) + '<br>';
newContent += servResponse.trips.tripOption[0].saleTotal + '<br>';
newContent += '</div>';
}
document.getElementById('content').innerhtml = newContent;
}
Unfortunately, this does not write out anything to the webpage. So far I can only view the raw JSON results in the Chrome Developer's Toolbar Console.
Can someone please help identify what I need to do differently?
Thanks in advance!
Assuming you have an element on the page with the ID of content, it should work fine, you just have a little typo
document.getElementById('content').innerhtml = newContent;
capitlize the 'HTML',
document.getElementById('content').innerHTML = newContent;
$('#content').load('resultsPage.html #content'); looks incorrect, the 1st parameter should just be a URL. Try commenting it out, for now, since you're changing it's content with the other line.
Also, the 4th line should be:
for(var i = 0; i < servResponse.trips.tripOption.length; i++){
You have:
... tripOption[i].length ...
The function below should:
Create one div with the class="results"
Place several p elements inside this div, each containing a 2-line entry
Display all this inside the element with an id of "content"
Is this what you want? The CSS that you are currently applying to .results may need to be applied to .results p instead.
function successFunction(servResponse){
var tripOption = servResponse.trips.tripOption;
var newContent = '<div class="results">';
for(var i = 0; i < tripOption.length; i++){
newContent += '<p>' + "Option " + (i+1) + '<br>';
newContent += tripOption[i].saleTotal + '<p>';
}
newContent += '</div>';
document.getElementById('content').innerHTML = newContent;
}
jsFiddle
var servResponse = {
"kind": "#tripsSearch",
"trips": {
"kind": "#tripOptions",
"tripOption": [
{
"saleTotal": "USD294.10",
"id": "DMfSXrkVQGKTVQsDD5l60N004",
},{
"saleTotal": "USD333.10",
"id": "DMfSXrkVQGKTVQsDD5l60N002",
},
{
"saleTotal": "USD225.94",
"id": "DMfSXrkVQGKTVQsDD5l60N005",
}
]
}
};
function successFunction(servResponse) {
var newContent = '';
servResponse.trips.tripOption.forEach(function(el,index){
newContent += '<div class="results">';
newContent += '<p>' + "Option " + (index+1) + '<br>';
newContent += el.saleTotal + '<br>';
newContent += '</div>';
console.log(el.saleTotal);
});
document.getElementById('content').innerHTML = newContent;
}
successFunction(servResponse);
Using pure javascript forEach loop
Example Link : http://jsfiddle.net/c1wzsqaf/1/
I've been learning and I think I'm finally at the end of this little "project" I've been struggling with! I've seen a few similar topics but can't quite adapt the code for my needs!
I have a JSON output that displays correctly, and I'm looking to search through it for a specific value, and only paste those results in the table.
I have the following Javascript that takes XML data and pastes it into a table.
Javascript
var html = '<table id="myTable"><thead><tr><th>Entry</th>';
for ( row = 0; row < jsondata.rowCount; row++ )
{
html += "<tr><td>" + (row+1) + "</td>";
for ( column = 0; column < jsondata.columnCount; column++ )
{
if((jsondata.xmlData [ row ] [ column ]) == "Ninja")
{
html += "<td>" + jsondata.xmlData [ row ] [ column ] + "</td>"
}
alert(jsondata.xmlData [ row ] [ column ]); //Added in edit - "undefined"
}
html += "</tbody></table>";
$("#tablearea").html(html);
}
EDIT: JSON
"xmlData" : [ [ "Ninja", "Blue"], [ "Car", "Red"] ]
If I exclude the if statement it will paste it all, but the if (when tested with an alert) states undefined.
EDIT (MORE CONCISE):
I believe that your problem is that your rowCount member does not match your actual number of rows. You could use the .length property of an array, or (in your given object), you could do the following...
var jsondata = {
rowCount: 3,
columnCount: 2,
xmlData: [["Ninja", "Blue"], ["Car", "Red"]]
};
var html = '<table id="myTable">' +
'<thead>' +
'<tr><th>Entry</th><tr>';
html += "<tbody>";
for (row = 0; row < jsondata.rowCount; row++) {
var showRow = false;
var tempHtml = "<tr>";
for (column = 0; column < jsondata.columnCount; column++) {
if (jsondata.xmlData[row]) {
tempHtml += "<td>" + jsondata.xmlData[row][column] + "</td>";
showRow = (jsondata.xmlData[row][column] == "Ninja") || showRow;
}
}
tempHtml += "</tr>";
if (showRow) {
html += tempHtml;
}
}
html += "</tbody></table>";
$("#tablearea").html(html);
It seem you have rowCount and/or columCount not matching (maybe just switched) with the actual length of the arrays.
Anyway I'd suggest to retrieve the length of the arrays inspecting them directly
var html = '<table id="myTable"><thead><tr><th>Entry</th>';
for ( row = 0; row < jsondata.xmlData.length; row++ )
{
html += "<tr><td>" + (row+1) + "</td>";
for ( column = 0; column < jsondata.xmlData[row].length; column++ )
{
if((jsondata.xmlData [ row ] [ column ]) == "Ninja")
{
html += "<td>" + jsondata.xmlData [ row ] [ column ] + "</td>"
}
}
html += "</tbody></table>";
$("#tablearea").html(html);
}