Coffeescript : For loop to concatenate HTML <td> element - javascript

Playing around a coffeescript. I have the following for loop to concat a html element in native javascript which works well. At the moment I just couldnt get the value json data i.e i.a , i.b from coffeescript.
//.js file
function createTr(json){
var tr='';
for (var i=0;i<json.data.length;i++){
var data ='<tr><td>' + json.data[i].a + ' - ' + json.data[i].b +
'</td>'+
'<td>' + json.data[i].c +
'</td>'+
'<td>' + json.data[i].d +
'</td>'+
'</tr>';
tr +=data;
}
return tr;
}
The coffescript is per below
//.coffeescript
createTr = (json) ->
tr=''
tr + '<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data
tr
the source map for the autogenerated javascript from the coffeescript as per below
//autogenerated js file from coffeescript file above
createTr = function(json) {
var i, j, len, ref, tr;
tr = '';
ref = json.data;
for (j = 0, len = ref.length; j < len; j++) {
i = ref[j];
tr + '<tr><td>' + i.a + '-' + i.b + '</td><td>' + i.c + '</td><td>' + i.d + '</td></tr>';
}
return tr;
};

The only difference is a missing assignment. The CoffeeScript version should be:
createTr = (json) ->
tr=''
tr += '<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data
tr

##.coffee file
createTr = (json) ->
tr = ''
for item in json.data
data = """<tr>
<td>#{item.a}-#{item.b}</td>
<td>#{item.c}</td>
<td>#{item.d}</td></tr> """
tr += data
return tr
And read http://coffeescript.org/ about loop, string and variables in string like "Some text #{variable}"

I prefer to use a join on the array that the for loop creates:
createTr = (json) ->
('<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data).join("")
or kind of like #yavor.makc if it was my code I might focus on readability:
createTr = (json) ->
(for i in json.data
"
<tr>
<td>#{i.a}-#{i.b}</td>
<td>#{i.c}</td>
<td>#{i.d}</td>
</tr>
"
).join("")

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

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

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

How can i update data in html after modify the object?

I have this function that modify my existing object by ID :
var updateUser = function () {
var id = $("#userId").val();
var user = findObjectById(id);
user.username = $('#username').val();
user.level = $('#level').val();
user.regstatus = $('#regstatus').val();
user.regdate = $('#regdate').val();
$(".table").show();
$("#newUser").show();
$("#userForm").hide();
$("#updateUser").hide();
};
How can i replace my curent data from HTML with modified data ?
This is my function for creating rows :
var buildRow = function (data) {
var html = '<tr id = ' + data.id + '>' +
'<td>' + data.username + '</td>' +
'<td>' + data.level + '</td>' +
'<td>' + data.regstatus + '</td>' +
'<td>' + data.regdate + '</td>' +
'<td>' +
'<button class="btn btn-info"value="Edit" onclick="userList.editUser(' + data.id + ')">Edit</button>' + ' ' +
'<button class="btn btn-danger" value="Delete" onclick="userList.deleteRow(' + data.id + ')">Delete</button>' + '</td>' +
'</tr>';
$("#users").append(html);
};
P.S i want to update in the same place and my id should be the same.
I modified your prototype jsFiddle a bit, so it contains a working example.
I needed to modify some parts to get it work, for example updating the object I added a function.
updateObjectById = function (id, obj){
for (var i = 0, l = userData.length; i < l; i++) {
if (userData[i].id == id) {
userData[i] = obj;
}
}
};
You should be able to work it out I guess, by the given jsFiddle
As I understand it you want to update the table when running "updateUser". There are basically three ways to update the data in your case.
Rebuild the whole row
Pick out specific cells in the table and change the content
Use a two way databinding framework
In my experience the best solution, and how f.ex. Backbone does it, is just recreating all the HTML when your data changes. two way databinding is even more powerful, but seems overkill in this situation.
So basically in your updateUser function:
var row = buildRow(user);
var $existingRow = $(id);
if ($existingRow.length) {
$existingRow.replaceWith(row);
} else {
$('#users').append(row);
}
Now, this of course requires a change to your "buildRow" function, not making it append the row, but return it.
Hope this gets you further...

Categories