Getting JSON data in HTML table format - javascript

This is my code and I am trying to pull in JSON data from an API.
The data is being successfully pulled but it is not coming in table format. It is coming as a continuous horizontal string.
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
var respoTxt = xhttp.responseText;
var myObj = JSON.parse(respoTxt);
document.getElementById("demo").innerHTML = '<table><tr><thead>' +
myObj["dataset"]["column_names"][5] + '</thead><thead>' + myObj["dataset"]
["column_names"][6] + '</thead></tr>';
myObj["dataset"]["data"].forEach(function(p, i) {
//Below is 1st code version:
// var tr = document.createElement("tr");
// document.getElementById("demo").appendChild(tr);
// var td1 = document.createElement("td");
// tr.appendChild(td1);
// var td2 = document.createElement("td");
// tr.appendChild(td2);
// td1.innerHTML = myObj["dataset"]["data"][i][5];
// td2.innerHTML = myObj["dataset"]["data"][i][6];
document.getElementById("demo").innerHTML += '<tr>';
document.getElementById("demo").innerHTML += '<td>' + myObj["dataset"]
["data"][i][5] + '</td>';
document.getElementById("demo").innerHTML += '<td>' + myObj["dataset"]
["data"][i][6] + '</td>';
document.getElementById("demo").innerHTML += '</tr>';
//Here's the 3rd code version:
// document.getElementById("demo").innerHTML += '<tr><td>' +
myObj["dataset"]["data"][i][5] + '</td><td>' + myObj["dataset"]["data"][i]
[6] + '</td></tr>';
});
document.getElementById("demo").innerHTML += '</table>';
}
I have used 3 different types of code inside (2 of them marked in comments above and below the active one).
None of them are showing the data in table format.
Here's the Codepen.

The problem is that when you set the innerHTML of an element, the browser automatically closes any unopened tags, because it has to parse whatever you've assigned as complete HTML. So you can't concatenate the opening tag, contents, and closing tags in separate assignments.
The solution is to assign all the HTML to a string variable as you're building it up, then assign that to .innerHTML at the very end. This is also more efficient, since it doesn't have to keep parsing HTML.
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
var respoTxt = xhttp.responseText;
var myObj = JSON.parse(respoTxt);
var html = '<table><tr><thead>' +
myObj["dataset"]["column_names"][5] + '</thead><thead>' + myObj["dataset"]
["column_names"][6] + '</thead></tr>';
myObj["dataset"]["data"].forEach(function(p, i) {
html += '<tr>';
html += '<td>' + myObj["dataset"]
["data"][i][5] + '</td>';
html += '<td>' + myObj["dataset"]
["data"][i][6] + '</td>';
html += '</tr>';
});
html += '</table>';
document.getElementById('demo').innerHTML = html;
}

Little bit modification to your code.
Please use it in the below manner
document.getElementById("demo").innerHTML = '<table><thead><tr><th>' +
myObj["dataset"]["column_names"][5] + '</th><th>' + myObj["dataset"]
["column_names"][6] + '</th></tr></thead>';

Related

Javascript Append Function, Need to build a loop

I have a .php file where I am using both HTML and JavaScript to display items from my database. I have a JavaScript append function that is creating cards where each item is display. On my cards, I have a button that will expand the card to show product history. Some products have more history than others so the expansion needs to be dynamic. The historical data is being pulled from database and is initially in a php array. I originally was going to institute php into the javascript append function but I could not figure out how to set the JavaScript index variable 'I' to my php index. So I want to just stay with JavaScript. But I don't know how to write a loop in the middle of this append function that will loop through the historical array and populate the expansion. Below is what I am attempting. I took out a lot of the lines in the append function but you can see what I am trying to do.
function get_products() {
clear_cards();
$.each(productNumbers,
function(i, value) {
$('.main_card_shell').append(
"<div class='card_content card_style' id='card" + i + "'>" +
"<div id='card_tab2" + i + "' class='tabcontent' data-tab='tab-name2'>" +
"<div class='details_tables'>" +
"<table>" +
"<tr>" +
"<th>Item Type</th>" +
"<th>Painted</th>" +
"<th>Last Sold" +
"<a id='_close_tab" + i + "' class='tablinks tab_override' onclick=\"openCity(event,'card_tab4" + i + "')\">" +
"<i class='large angle up icon'></i>" +
"</a>" +
"</th>" +
"</tr>" +
"<tr>" +
var itemdatesplit = itemdate[i].split("$$");
var itemtypesplit = itermtype[i].split("$$");
var itemsplit = item[i].split("$$");
var arraylength = itemsplit.length;
var counter = 0;
while(counter < arraylength)
{
+ "<td>" + itemtypesplit[counter] + "</td>" +
+ "<td>" + itemdatesplit[counter] + "</td>" +
counter = counter + 1;
}
+
"</tr>" +
"</table>" +
"</div>" +
"</div>" +
Please help. I had it working with PHP inserted in, but I just couldn't figure out how to set it to a PHP variable.
Place this code into a function:
function getSomething(i) {
var html = '';
var itemdatesplit = itemdate[i].split("$$");
var itemtypesplit = itermtype[i].split("$$");
var itemsplit = item[i].split("$$");
var arraylength = itemsplit.length;
var counter = 0;
while(counter < arraylength) {
html += "<td>" + itemtypesplit[counter] + "</td>";
html += "<td>" + itemdatesplit[counter] + "</td>";
counter = counter + 1;
}
return html;
}
And then use it in your HTML building block:
'<some html>' + getSomething(i) + '<some other html>'

$.getJSON and for loop with an array and how to get them to work together - for loop completes before JSON is returned

I am trying to cycle through an array and with each value in the array, use $.getJSON to return some JSON and populate an HTML table with the return values.
I have been following this post, but seem not get this to work:
$.getJSON calls misbehaving inside a for loop
Here is my function:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
});
The userProviderKeys value is 0be32d8057924e718a8b6b4186254756,2dc5f826601e4cc5a9a3424caea4115f
The code never makes the $.getJSON call it just completes the for loop.
How do I update this code to get the first value in the array, grab the JSON, create the HTML, and then cycle through the loop?
I have tried setTimeout but that didn't help me out.
If you have some ideas, could you update my existing code - I understand better when I see the code itself. Thanks.
I don't know why you're doing this using queues. But you are, so I'm not going to rewrite your code to do it some other way.
The last few lines need to be called after all the queued functions have run, which means they should be called asynchronously. (Yes, you could make the whole thing synchronous as Marcus Höglund suggested, but that's no way to write scalable applications in javascript.) You could do this by adding another function to the queue containing these lines. Like this:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
focus.queue('apicalls', function(next) {
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
next();
});
});
Edit: Sunshine has pointed out that the linked stackoverflow post has mysterious references to the .dequeue method. In the accepted answer, this method is called explicitly after the tasks have been queued. I don't know whether this was necessary or not. I had thought that the problem was that the $.json bit wasn't happening until after the $("#tableProviderSelect tbody").html(tableHTML); part. But now I realise you wrote: "The code never makes the $.getJSON call it just completes the for loop." In that caseSunshine may have been right, and you need to add focus.dequeue('apicalls'); just after the last focus.queue(...);.

How do I mail cell range with proper format in google sheet?

Hi this is my sheet: https://docs.google.com/spreadsheets/d/1xkTt_1kLyROkUFComi8-NiKyDMan6617C1dA5UqWTSI/edit?usp=sharing
I want to share range A2:F8 in email using google script.
As far as I can say this script works fine:
function sendMail(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sh.getRange("A2:O38").getValues();
//var htmltable =[];
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;'
var htmltable = '<table ' + TABLEFORMAT +' ">';
for (row = 0; row<data.length; row++){
htmltable += '<tr>';
for (col = 0 ;col<data[row].length; col++){
if (data[row][col] === "" || 0) {htmltable += '<td>' + 'None' + '</td>';}
else
if (row === 0) {
htmltable += '<th>' + data[row][col] + '</th>';
}
else {htmltable += '<td>' + data[row][col] + '</td>';}
}
htmltable += '</tr>';
}
htmltable += '</table>';
Logger.log(data);
Logger.log(htmltable);
MailApp.sendEmail("myemail#gmail.com", 'Daily report','' ,{htmlBody: htmltable})
}
The problem is when i get mail the merged cells are not in merged state.
This result in 3 columns instead of 1.
Can someone please tweak the code so that I get exactly like i formatted sheets.
I modified the code a little because I didn't want to send any emails. And if you'll move the table up to the top left corner and use sh.getDataRange() then you'll get the entire table with no problems.
This is my modified version.
function sendSomething(){
var sh = SpreadsheetApp.getActiveSheet();
var dataA = sh.getDataRange().getValues();
var None = ' ';
var htmltable ='';
var TABLEFORMAT = 'cellspacing="2" cellpadding="2" dir="ltr" border="1" style="width:100%;table-layout:fixed;font-size:10pt;font-family:arial,sans,sans-serif;border-collapse:collapse;border:1px solid #ccc;font-weight:normal;color:black;background-color:white;text-align:center;text-decoration:none;font-style:normal;'
var htmltable = '<table ' + TABLEFORMAT +' ">';
for (row = 0; row<dataA.length; row++)
{
htmltable += '<tr>';
for(col = 0 ;col<dataA[row].length; col++)
{
if (dataA[row][col] === "" || 0)
{
htmltable += '<td>' + None + '</td>';
}
else
if (row === 0)
{
htmltable += '<th>' + dataA[row][col] + '</th>';
}
else
{
htmltable += '<td>' + dataA[row][col] + '</td>';
}
}
htmltable += '</tr>';
}
htmltable += '</table>';
dispStatus('HTML',htmltable,800,500);
}
And this is my display routine which I incorporated into your code. It's just my version of the logger.
function dispStatus(title,html,width,height,modal)
{
var title = typeof(title) !== 'undefined' ? title : 'No Title Provided';
var width = typeof(width) !== 'undefined' ? width : 400;
var height = typeof(height) !== 'undefined' ? height : 300;
var html = typeof(html) !== 'undefined' ? html : '<p>No html provided.</p>';
var modal = typeof(modal) !== 'undefined' ? modal : false;
var htmlOutput = HtmlService
.createHtmlOutput(html)
.setWidth(width)
.setHeight(height);
if(!modal)
{
SpreadsheetApp.getUi().showModelessDialog(htmlOutput, title);
}
else
{
SpreadsheetApp.getUi().showModalDialog(htmlOutput, title);
}
}
You still need to format the dates. Perhaps you can use Utilities and if you want to merge cells together in the header you'll need to figure out which ones to give a colspan="3".

How to optimize the DOM inserting loop

For example : I want to insert many tr in a table like this
var tbody = $('#tbody')
// Suppose the articlelist is the data from ajax
while (articlelist.length > 0) {
var article = articlelist.shift(),
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}
To avoid create the <tr>...</tr> in loop .Is it possible to use a class to generate the tr content ?
An optimized version:
var tbody = $('#tbody'),
htmlStr = "";
for (var i = 0, len = articlelist.length; i < len; i++) { // avoid accessing 'length' property on each iteration
htmlStr += '<tr><td>' + articlelist[i].id + '</td>'
+ '<td>' + articlelist[i].channelid + '</td>'
+ '<td>' + articlelist[i].comment + '</td>'
+ '<td>' + articlelist[i].last_edit_time + '</td><td><tr>';
}
tbody.append(htmlStr); // parses the specified text as HTML or XML and inserts the resulting nodes
You could use a loop to concatenate all the strings, then append this lengthy string all at once. This would help with performance for many trs
var tbody = $('#tbody')
var rows = ''
while (articlelist.length > 0) {
var article = articlelist.shift(),
rows += '<tr><td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><tr>';
}
tbody.append(rows)
add a function like this to do this for you.
while (articlelist.length > 0) {
make_content(article);
}
function make_content(article) {
var tbody = $('#tbody');
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}

Howto return formated HTML-code with a javascript function

This question is bothering me for quite some time.
Is there a better way to do this, because this is very difficult to code and to maintain?
function format_details ( d ) {
var r = '';
var vaste_afspraak = (d.werkbon.werkbonafspraaktype_id == 1)? 'JA': 'NEE';
r += '<div class="well no-padding"><table id="dt_details" class="table table-bordered table-condensed" class="display" width="100%">';
r += '<tbody>';
r += '<tr>';
r += '<th colspan="2" class="text-center">#' + d.werkbon.id + ' - Details werkbon ' + d.werkbon.nummer + '</th>';
r += '</tr>';
r += '<tr>';
r += '<th style="width:20%;">Locatie naam</th>';
r += '<td>' + d.werkbon.locatie_naam + '</td>';
r += '</tr>';
r += '<tr>';
r += '<th>Adres</th>';
r += '<td>' + d.werkbon.locatie_adres + '</td>';
r += '</tr>';
r += '<tr>';
r += '<th>PC Plaats</th>';
r += '<td>' + d.werkbon.locatie_postcode + ' ' + d.werkbon.locatie_woonplaats + '</td>';
r += '</tr>';
r += '</tbody>';
r += '</table></div>';
return r;
}
People suggest using <script src="..."> and <link rel="stylesheet" href="..." /> for a reason: separation of HTML, JavaScript and CSS.
I would suggest not dumping large amounts of HTML into your JavaScript file for much the same reason.
Instead, consider having the HTML defined in your HTML. One technique might be:
<script type="text/html" id="template-details">
<div><table><whatever>
<th>Adres</th>
<td>{{locatie_adres}}</td>
</whatever></table></div>
</script>
Then in your JavaScript, you can do this:
var r = document.getElementById('template-details').innerHTML;
r = r.replace(/\{\{([a-z0-9_]+)\}\}/g,function(_,key) {
return d.werkbon[key];
});
return r;
This way you have a template saved in your HTML, which will be much easier to manage, and the JavaScript will just take that and put in the data before outputting it.
Personally though, I think a more sensible option would be to send an AJAX request to the server to get the data, and the server can send that data in all its HTML glory.
Although there really isn't any need to format code out from JS to HTML (whitespace is ignored in the browser), you can do this by printing out tabs (\t) as necessary.
EDIT I assumed at first that you wanted to format the outputted HTML, but if you wanted to format the JS function as well, look at the following:
For example:
function format_details ( d ) {
var vaste_afspraak = (d.werkbon.werkbonafspraaktype_id == 1)? 'JA': 'NEE';
return '<div class="well no-padding"><table id="dt_details" class="table table-bordered table-condensed" class="display" width="100%">' +
'\t<tbody>' +
'\t\t<tr>' +
'\t\t\t<th colspan="2" class="text-center">#' + d.werkbon.id + ' - Details werkbon ' + d.werkbon.nummer + '</th>' +
'\t\t</tr>' +
'\t\t<tr>' +
'\t\t\t<th style="width:20%;">Locatie naam</th>' +
'\t\t\t<td>' + d.werkbon.locatie_naam + '</td>' +
'\t\t</tr>' +
'\t\t<tr>' +
'\t\t\t<th>Adres</th>' +
'\t\t\t<td>' + d.werkbon.locatie_adres + '</td>' +
'\t\t</tr>' +
'\t\t<tr>' +
'\t\t\t<th>PC Plaats</th>' +
'\t\t\t<td>' + d.werkbon.locatie_postcode + ' ' + d.werkbon.locatie_woonplaats + '</td>' +
'\t\t</tr>' +
'\t</tbody>' +
'</table></div>';
}
You don't need the r += on each line; just add it all together in one statement. Also,you don't need the r at all; just return the value instead of creating an extra variable.
A solution could be store in a html file your template than make an ajax call to retrieve the html and use jquery to change the dynamic content through id or class attribute. The code could be something like this
$.ajax({
async:false,
url: "fileURL",
contentType: "text/plain",
type: "GET" ,
dataType:"text",
success: function(result) {
$(result).find(".text-center").text("enter the text with your variable");
return $(result).html();
},
error: function(error){
alert (error);
}
});
Please double check the syntax. I didn't tried it

Categories