Need help using a 'for loop' extracting data from a Table - javascript

Just wondering if anyone can help me.
I have created a table, and using Javascript I am extracting all the data and placing it into divs.
$(function () {
$('table').each(function () {
var output = "",
table = $(this),
rowHead = table.find('tbody tr th'),
rowSubject = table.find('thead tr th:not(:first-child)'),
rowContent = table.find('tbody tr td'),
copy = table.clone();
output += '<div class="mobiled-table">';
for (i = 0; i < rowHead.length; i++) {
output += '<div class="head">' + $(rowHead[i]).html() + '</div>';
for (j = 0; j < rowSubject.length; j++) {
output += '<div class="subject">' + $(rowSubject[j]).html() + '</div>';
output += '<div class="content">' + $(rowContent[i]).html() + '</div>';
}
}
output += '</div>';
$('table').append(output);
});
});
It all works great except the .content class isnt working correctly. I believe I am using the wrong 'for loop' or I need to create another 'for loop'. Please take a look at my codepen and you will see my problem
http://codepen.io/anon/pen/JrKBf
I hope someone can help.

Because rowContent contains the matrix of cells but as a one dimension array, you have to translate (i, j) to a valid index for rowContent which is (i * 4) + j:
rowContent[i]
should be replaced by:
rowContent[(i*4) + j]

In a simpler way, you can do like this,
var container=$("#container");
$("table tr:not(:first)").each(function() {
var heading = $(this).find("th").html();
container.append('<div class="subject">' + heading + '</div>');
$(this).find("td").each(function(i) {
container.append('<div class="subject">' + $("table th").eq($(this).index()).html() + '</div>');
container.append('<div class="content">' + $(this).html() + '</div>');
});
});
Fiddle

Related

$.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(...);.

jQuery append td to dynamically created tr

I have a div with a table and I'd like to append a row with multiple td to it:
var $tblBody = $('#' + btn.attr('data-tbody-id')); //tbody of the Table
// Append the Row
$tblBody.append('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
var $tblRow = $('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
//Loop through my data and append tds
$.each(data.extra.fields, function (i, v) {
console.log(i); //Shows 0,1,2,3 etc.
$tblRow.append('' +
'<td class="' + v.cellClass + '">' +
' <span class="'+data.extra.span+'_'+v.name+'_'+data.extra.id+'">' + v.value + '</span>' +
'</td>'
)
});
Unfortunately the created to stays empty:
<tr id="row_ZWxoQXArUi82K3BjaFY4Y0x2ZWR3UT09_41_temp"></tr>
I found this: https://stackoverflow.com/a/42040692/1092632 but why is the above not working for me?
First make the tds of the row, after that append whole tr to the body.
Remove this line
$tblBody.append('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');,
because you don't have a reference on it and use append part of your code after the loop.
var $tblRow = $('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
$.each(data.extra.fields, function (i, v) {
console.log(i); //Shows 0,1,2,3 etc.
$tblRow.append('' +
'<td class="' + v.cellClass + '">' +
' <span class="'+data.extra.span+'_'+v.name+'_'+data.extra.id+'">' + v.value + '</span>' +
'</td>'
)
});
$tblBody.append($tblRow); // <-----------------------
This line
var $tblRow = $('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
creates a new reference which is not in DOM yet.
instead, replace it with this
var $tblRow = $tblBody.find( "#row_' + data.extra.span + '_' + data.extra.id + '_temp">');
This will now get you the handle to the same row which has already been appended to the DOM.
Here you with one more solution using ES6 template literals
var $tblBody = $('#' + btn.attr('data-tbody-id')); //tbody of the Table
// Append the Row
var rowid = 'row_' + data.extra.span + '_' + data.extra.id + '_temp';
$tblBody.append(`<tr id=${rowid} />`);
//Loop through my data and append tds
$.each(data.extra.fields, function (i, v) {
console.log(i); //Shows 0,1,2,3 etc.
$(`#${rowid}`).append(
`<td class="${v.cellClass}">
<span class="${data.extra.span}_${v.name}_${data.extra.id}">
${v.value}
</span>
</td>`);
});
Once you appended the tr then use the id instead of get the row & appending the td.
Hope this will help you.
change the code to something like this
var $tblBody = $('#' + btn.attr('data-tbody-id')); //tbody of the Table
// Append the Row
$tblBody.append('<tr id="row_'+data.extra.span+'_'+data.extra.id+'_temp"></tr>');
var $tblRow = $('#'+'row_'+data.extra.span+'_'+data.extra.id+'_temp');
//Loop through my data and append tds
$.each(data.extra.fields, function (i, v) {
console.log(i); //Shows 0,1,2,3 etc.
$tblRow.append('' +
'<td class="' + v.cellClass + '">' +
' <span class="'+data.extra.span+'_'+v.name+'_'+data.extra.id+'">' + v.value + '</span>' +
'</td>'
)
});
You forgot to append tblRow to the tblBody. Adding the last line would fix your code
// Append the Row
$tblBody.append('<tr
id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
var $tblRow = $('<tr
id="row_'+data.extra.span+'_'+data.extra.id+'_temp">');
//Loop through my data and append tds
$.each(data.extra.fields, function (i, v) {
console.log(i); //Shows 0,1,2,3 etc.
$tblRow.append('' +
'<td class="' + v.cellClass + '">' +
' <span
class="'+data.extra.span+'_'+v.name+'_'+data.extra.id+'">' + v.value +
'</span>' +
'</td>'
)
});
$tblBody.append($tblRow);

javascript/json nested for and for/in loops in framework7 popups

Hi all I hope someone can help Im a bit stuck single developer on own , with the below what im trying to do is nest for loops, I have data back at the var = I; but not at the next two for statements, when the popup is called only the last record comes back I can see in console the data is there and the ids for the link and the data within do illicitate around , however only the last record appears I haven't uploaded the json because its a really long script any help on this would be very appreciated I have been playing with nested loops and got them to work just not in the bellow I normally use for/in apparently that's bad practice from what ive read up so changed to flat for loops.
<pre> $.getJSON('myurl', function (data) {
console.log(data);
var data = data.sponsor;
var output = "";
var myApp = new Framework7();
var $$ = Dom7;
output += "<ul>";
for (var i = 0; i < data.length; i++) {
output += "<li class='list-block media-list sponsors list-block-search '>";
output += "<div class='item-media-auto'>" + data[i].images + "</div>"; //working
output += "<div class='item-inner'>";
output += "<div class='item-title-row'>";
output += " <div id='name' class='item-title'>" + data[i].title + data[i].id +"</div>";
output += "</div>";
output += "<a href=" + data[i].custom['panaone_sponsorurl'] + " target='_blank'>";
output += data[i].custom['panaone_sponsorurl'];
output += "</a>";
output += ' <p>Create Popup</p>';
output += "</li>";
document.getElementById("placeholder").innerHTML = output;
output += "</ul>";
}
for (var l = 0; l < data.length; l++) {
$$('.create-popup'+ data[l].id).on('click', function () {
for (var j = 1; j < data.length; j++) {
var popupHTML = '<div class="popup '+ data[j].id + '">'+
'<div class="content-block ">'+
'<p>Popup created dynamically.'+ data[j].id + '</p>'+
'<p>Close me</p>'+
'</div>'+
'</div>'+
myApp.popup(popupHTML);
}
});
}
});
}
</pre>

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)
}

Add a Click Event to elements added to the DOM

var myOP = '<div>';
for (var i = 0; i < op.length; i++) {
myOP += '<div>';
myOP += '<div id="myBTN-' + [i] + '">' + op[i]['Field1'] + '</div>';
myOP += '<div id="blah-' + [i] + '">' + op[i]['Field2'] + '</div>';
myOP += '</div>';
}
myOP += '</div>';
$("#myBTN-" + i).click(function () {
$('#blah-' + i).toggle("slow");
});
$('#container').html(myOP);
I'm trying to get the click function to fire on the elements i'm created w/ the above for loop. Can anyone point me in the right direction?
As long as the element is just a String, you won't be able to add a handler. You have to add the handler after $('#container').html(myOP);
You could try exploring the idea of event delegation. Using that, your could do something like:
$('#container').on('click', function(e){
e = e || event;
var from = e.target || e.srcElement, i;
if (from.id && /^mybttn/i.test(from.id)){
i = +((from.id.match(/\d{0,}$/)||[-1])[0]);
if (i>=0){
$('#blah'+i).toggle('slow');
}
}
});​
​Demo
Alternatively you could
$('#container').html(myOP);
$('div[id^="myBTN-"]').on('click',function(){
$('#blah-' + this.id.match(/\d{0,}$/)[0]).toggle("slow");
});
after you save the html into #container use this:
$('[id^="myBTN-"]', '#container').click(function () {
$(this).closest('[id^="blah-"]').toggle('slow');
});
jQuery's .on() method will bind to appended elements if used properly. http://api.jquery.com/on/
<div id="existingParent">
<!--<div class="added-later">Hi!</div>-->
<!--<div class="added-later">Hi!</div>-->
</div>
To listen for events on the added-later elements
$('#existingParent').on('click hover','.added-later', myFunction);
The method must be bound to an element that exists. $('body') can be used here, but at the cost of some performance I'd imagine.
Do something like this:
var myOP = '<div>';
for (var i = 0; i < op.length; i++) {
myOP += '<div>';
myOP += '<div id="myBTN-' + [i] + '">' + op[i]['Field1'] + '</div>';
myOP += '<div id="blah-' + [i] + '">' + op[i]['Field2'] + '</div>';
myOP += '</div>';
}
myOP += '</div>';
$(myOP).appendTo('#container').find('div[id^="myBTN"]').click(function () {$(this).next().toggle("slow")});
When you re trying to attach events added dynamically, a simple .click() won't do, you have to use on:
$("#newElementparent").on('click', "#newElement", function() {});
You'd do better to build the element on the fly:
var container = $('<div>');
for (var i = 0; i < op.length; i++) {
container.append(
$('<div>').append(
$('<div>').text(op[i]['Field1']).click(function() {
$(this).next('div').toggle("slow");
}),
$('<div>').text(op[i]['Field2'])
)
);
}
$('#container').empty().append(container);

Categories