I have this Javascript function which creates a table in html. Which does exactly what I want.
var thead = '<table><thead><tr><td>#</td><td>Name</td><td>Id</td></tr></thead><tbody>\n';
for(var i=0; i<dataArray.length; i++)
{
tbody += '<tr class="row">';
tbody += '<td>' + (i+1) + '</td>';
tbody += '<td>' + dataArray[i].Device_Name + '</td>';
tbody += '<td>' + dataArray[i].Device_Id + '</td>';
tbody += '</tr>\n';
}
var tfooter = '</tbody></table>';
document.getElementById('dataTableDiv').innerHTML = thead + tbody + tfooter;
Now I want to run some code everytime I click on a certain row. For now it doesn't matter which row is click as long as the code is being executed. Here is the code that should handle the row click. All the other click actions work perfectly inside the $(document).ready(function(){}); But for some reason, the click handler for the table doesn't work.
$(document).ready(function()
{
$(".row").click(function()
{
console.log("Blablabla")
});
});
What am I doing wrong?
Because you are generating HTML dynamically from Jquery so try event delegation as shown below :-
$(document).on('click','.row',function(){
// Your Code...
});
OR
$(document.body).on('click','.row',function(){
// Your Code...
});
OR(adding Jai's useful comment in answer)
$('#dataTableDiv').on('click','.row',function(){
// Your Code...
});
Related
I have a live listener on my database data in my HTML table that is generated by javascript and when I add a new entry or delete an old entry, the data that was previously in the table gets duplicated.
var database = firebase.database().ref().child('transactions');
database.on('value', function(snapshot){
if(snapshot.exists()){
var content = '';
snapshot.forEach(function(data){
var CustomerName = data.val().CustomerName;
var AmountSent = data.val().AmountSent;
var TimeEffected= data.val().TimeEffected;
var DateEffected = data.val().DateEffected;
var Successful = data.val().Successful;
content += '<tr>';
content += '<td>' + CustomerName + '</td>';//column2
content += '<td>' + AmountSent + '</td>'; //column1
content += '<td>' + TimeEffected + '</td>'; //column1
content += '<td>' + DateEffected + '</td>'; //column1
content += '<td>' + Successful + '</td>'; //column1
content += '</tr>';
});
$('#ex-table').append(content);
When it 'was database.once' and I had a refresh button I wouldn't get the data duplicated but I've changed it to'database.on' and now the data in the table duplicates whenever I do anything to the database.
I'm looking for the most cost-effective way.
I'm not sure which one of both 'database.once' or 'database.on' save money.
Since you listen to the value event on transactions, each time your callback is called the snapshot will contain all data under transactions. So any data that wasn't changed will also be in the snapshot, leading to it being in your table multiple times.
I see two options:
Wipe the table each time you get updated data
Perform more fine-grained updates
Wipe the table each time you get updated data
This is the simplest, since it requires the fewest changes to your existing code. Just clear the contents from the table whenever you get updated data from the database:
var database = firebase.database().ref().child('transactions');
database.on('value', function(snapshot){
$('#ex-table').empty(); // clear existing contents
if(snapshot.exists()){
var content = '';
snapshot.forEach(function(data){
var CustomerName = data.val().CustomerName;
var AmountSent = data.val().AmountSent;
var TimeEffected= data.val().TimeEffected;
var DateEffected = data.val().DateEffected;
var Successful = data.val().Successful;
content += '<tr>';
content += '<td>' + CustomerName + '</td>';//column2
content += '<td>' + AmountSent + '</td>'; //column1
content += '<td>' + TimeEffected + '</td>'; //column1
content += '<td>' + DateEffected + '</td>'; //column1
content += '<td>' + Successful + '</td>'; //column1
content += '</tr>';
});
$('#ex-table').append(content);
This should work fine, but repaints the entire table contents every time anything in there changes. This may result in noticeable flicker when the table is large.
Perform more fine-grained updates
The alternative is to perform more fine-grained updates. I.e. initially you add all children, after that you only add the new children, remove any data that gets removed from the database, etc.
Firebase has specific events for this purpose, which fire one level lower in the database. For example, the child_added event is defined as "fires initially for each node under the reference, and then each time a node is added under the reference". In the same vein there are child_removed, child_changed and child_moved events. With these events you can perform more granular updates to the table.
For example, here's how you'd handle child_added:
var database = firebase.database().ref().child('transactions');
database.on('child_added', function(snapshot){
var data = snapshot.val();
var content = '<tr id="'+snapshot.key+'">';
content += '<td>' + data.CustomerName + '</td>';
content += '<td>' + data.AmountSent + '</td>';
content += '<td>' + data.TimeEffected + '</td>';
content += '<td>' + data.DateEffected + '</td>';
content += '<td>' + data.Successful + '</td>';
content += '</tr>';
$('#ex-table').append(content);
});
Aside from cleaning up the code a bit, I also add the snapshot.key to the tr. This allows you to later look up the row for a key, just in case you get a child_changed, or child_removed event.
For example, here's how to remove the row from the table when it gets removed from the database:
database.on('child_removed', function(snapshot){
$('#'+snapshot.key).remove()
});
I have a piece of code that I am working with where the user can choose to download a "Slice" of a pie chart or the whole thing.
When they click on a slice, I send a variable called source which tells me which slice it came from.
Right now I am working on the "Download All" button. The source for this will be simply all.
This is what my loop looks like if the user selects slice:
// Loop over our data
$.each(seed.dataset,function(key, value){
if(this[col] == slice){
table += '<tr>';
table += '<td>'+this.escalationID+'</td>';
table += '<td>'+this.escReasonID+'</td>';
table += '<td>'+this.reasonText+'</td>';
table += '<td>'+this.escCreatedBy+'</td>';
table += '<td>'+this.escCreatorFirst+'</td>';
table += '<td>'+this.escCreatorLast+'</td>';
table += '</tr>';
}
});
The IF statement within the loop is what controls the data its including in the table variable. My question is, how can I choose when I want to enforce this IF statement or ignore it (allowing all data to be added to the table var)?
The obvious would be wrapping it in another IF statement but I feel there might be a cleaner way without having to duplicate all of the table data.
End result would be a bool saying if source=All include all the rows else if source=slice enforce the IF statement to include only the data we are looking for.
UPDATE
Essentially I am looking for a more clean way to do this:
// Loop over our data
$.each(seed.dataset,function(key, value){
if(source == 'slice'){
if(this[col] == slice){
table += '<tr>';
table += '<td>'+this.escalationID+'</td>';
table += '<td>'+this.escReasonID+'</td>';
table += '<td>'+this.reasonText+'</td>';
table += '<td>'+this.escCreatedBy+'</td>';
table += '<td>'+this.escCreatorFirst+'</td>';
table += '<td>'+this.escCreatorLast+'</td>';
table += '</tr>';
}
// We are downloading all so ignore the constraint
}else{
table += '<tr>';
table += '<td>'+this.escalationID+'</td>';
table += '<td>'+this.escReasonID+'</td>';
table += '<td>'+this.reasonText+'</td>';
table += '<td>'+this.escCreatedBy+'</td>';
table += '<td>'+this.escCreatorFirst+'</td>';
table += '<td>'+this.escCreatorLast+'</td>';
table += '</tr>';
}
});
You can use another boolean say ignoreAll as "OR" condition with existing if condition as shown below
// Loop over our data
var ignoreAll = true; // change its value as per your requirement
$.each(seed.dataset,function(key, value){
if(ignoreAll || this[col] == slice){
table += '<tr>';
table += '<td>'+this.escalationID+'</td>';
table += '<td>'+this.escReasonID+'</td>';
table += '<td>'+this.reasonText+'</td>';
table += '<td>'+this.escCreatedBy+'</td>';
table += '<td>'+this.escCreatorFirst+'</td>';
table += '<td>'+this.escCreatorLast+'</td>';
table += '</tr>';
}
});
$.each(seed.dataset,function(key, value){
if (source != 'slice' || this[col] == slice){
table += '<tr>';
// etc.
Alternatively:
$.each(seed.dataset,function(key, value){
if (source == 'all' || this[col] == slice){
table += '<tr>';
// etc.
Check out the below code.
If the current item is a slice, it's checked to make sure it is the correct slice. If it is, getSlice() is called and the $.each() loop breaks to avoid unnecessary iterations.
function getSlice(that) {
var table = '';
table += '<tr>';
table += '<td>' + that.escalationID + '</td>';
table += '<td>' + that.escReasonID + '</td>';
table += '<td>' + that.reasonText + '</td>';
table += '<td>' + that.escCreatedBy + '</td>';
table += '<td>' + that.escCreatorFirst + '</td>';
table += '<td>' + that.escCreatorLast + '</td>';
table += '</tr>';
return table;
}
// Loop over our data
$.each(seed.dataset, function (key, value) {
table += source == 'slice' ? (this[col] == slice ? true & getSlice(this) : false) : getSlice(this);
if (table === true) return false; // break out of loop
});
How I build my table:
for (var i = 0; i < result.length; i++) {
var item = result[i];
// Firma, BygningselementNavn, BrugerNavn, EmailAdresse, Telefon
tbody = tbody + '<tr class="modtagerRow"><td>' + item.FirmaNavn + '</td>' +
'<td>' + item.BygningselementNavn + '</td>' +
'<td>' + item.BrugerNavn + '</td>' +
'<td>' + item.EmailAdresse + '</td>' +
'<td>' + item.Telefon + '</td>'
// Medtag
tbody = tbody + '<td style="text-align:center"><input type="checkbox"
value="' + item.BygningselementId + '_' + item.BrugerId + '"
name="BygningsElementBrugerComboIds"></td>' + '</tr>';
}
$('#ModtagereTable tbody').append(tbody)
How I am trying to loop through the rows and adding a CSS class to rows that has it's checkbox checked.
1) I get the indexies to the console, but I can't make the if condition for all the checked checkboxes.
2) Also I am not sure if I can you $( this ) or I should use something else, when adding the class .hideForSendMailConfirm?
// Looping rows in table
$( ".modtagerRow" ).each(function(index, element) {
console.log('index: ' + index);
// if
if (element.checked) {
$( this ).addClass(".hideForSendMailConfirm");
}
});
Try this
$('.modtagerRow input:checked').closest('tr').addClass('hideForSendMailConfirm');
to add class to the rows that are not checked. You can use .not()
$('.modtagerRow input[type="checkbox"]').not(':checked').closest('tr').addClass('hideForSendMailConfirm');
Your code:
$(".modtagerRow").each(function (index, element) {
if (element.checked) {
$(this).addClass(".hideForSendMailConfirm");
}
});
is actually looping through the table row having class modtagerRow and a table row does not have any checked property and hence your code is not working.
You can do something like this:
$(".modtagerRow :checkbox").each(function (index, element) {
if (element.checked) {
$(this).closest(".modtagerRow").addClass("hideForSendMailConfirm");
}
});
This will loop through all the checkbox elements inside the table row and will check if it is checked or not and add the appropriate hideForSendMailConfirm class.
Also there is one more issue in your code:
.addClass(".hideForSendMailConfirm");
in order to add a class there is no need to add a . as prefix, we just pass the class name.
But again there is no need of looping here, you can just do this:
$(".modtagerRow :checkbox:checked").closest('tr').addClass('hideForSendMailConfirm');
As, when we call methods of a jQuery object, the elements referred to by the selector we passed to $() are looped through automatically and implicitly. Therefore, we can usually avoid explicit iteration, such as a each() loop here.
When I use this code, all the information is displayed in only one column. Also, if I check with Google Chrome, there are many <tbody> tags that were added to table.innerHTML .
http://puu.sh/4oLmM.png
How can I make it so it displays the header and each content[i] horizontally?
<table id="table1" border=\"5\" cellpadding=\"10\">
<script>
var table = document.getElementById('table1');
table.innerHTML = '';
var header = ['Method','Gp/Exp','Exp/H']
var content = [
['Kill',1,100],
['Die',42,1222],
['Yo',1,1245]
]
//Header
table.innerHTML += '<tr>';
for(var i in header){
table.innerHTML += '<th>' + header[i] + '</th>';
}
table.innerHTML += '</tr>';
//Content
for(var i in content){
table.innerHTML += '<tr>';
for(var j in content[i]){
table.innerHTML += '<td>' + content[i][j] + '</td>';
}
table.innerHTML += '</tr>';
}
</script>
I suspect this is what Ian meant:
var html = '<tr>';
for(var i in header){
html += '<th>' + header[i] + '</th>';
}
html += '</tr>';
for(var i in content){
html += '<tr>';
for(var j in content[i]){
html += '<td>' + content[i][j] + '</td>';
}
html += '</tr>';
}
table.innerHTML = html;
The way you've done it, you're adding badly formed HTML to the element. The overall string is fine, but my guess is that every time you do table.innerHTML +=, it realises that you're creating a dodgy HTML string, and messes around with it to get something that is valid HTML.
i have this situation:
...
for (var i = 0; i < json.length; i++)
{
output += '<tr>';
for ( var objects in json[i])
{
if (objects == 'amt_1')
{
output += '<td id="amt">' + json[i][objects] + '</td>';
}
}
output += '</tr>';
}
output += '<tr">';
var amt = 0;
$('#amt').each(function() {
amt += $(this).text();
});
output += '<td>' + amt + '</td>';
output += '</tr>';
$('#details').append(output);
}
this is a part of a table that give's me something like this:
<td id="amt">4.58</td>
<td id="amt">55.74</td>
<td id="amt">193.5</td>
<td></td>
and in the last td i would like the sum of the rest of them with the id = amt
what i have seems not to work
any ideas?
Thnaks
The problem is that you are using id's instead of classes, id's are supposed to be unique, so javascript only returns 1 td. Multiple elements however, can share the same class.
Also, the jQuery won't work because the elements haven't been added to the document yet.
for (var i = 0; i < json.length; i++)
{
output += '<tr>';
for ( var objects in json[i])
{
if (objects == 'amt_1')
{
output += '<td class="amt">' + json[i][objects] + '</td>';
}
}
output += '</tr>';
}
output += '<tr">';
$('#details').append(output); //Copied here, this will add the above elements
//to the document subtree, which allows jquery
//to search for them
output = ""; //Reset output
var amt = 0;
$('.amt').each(function() { //Changed to class selector
amt += parseInt($(this).text());
});
output += '<td>' + amt + '</td>';
output += '</tr>';
$('#details').append(output); //Append result
Like they said you should use a class instead of id
output += '<td class="amt">' + json[i][objects] + '</td>';
Then you must add the output to the DOM before your jQuery selector, $('.amt'), can find the elements
$('#details').append(output); //<--append BEFORE you select the .amt elements
var amt = 0;
$('.amt').each(function() {
amt += parseFloat($(this).html()); //parseFloat on the html
});
output = '<tr">'; //<-- reset output here
output += '<td>' + amt + '</td>';
output += '</tr>';
$('#details').append(output);
Still it would be better to just sum the amount in your for loop
var total = 0;
...
if (objects == 'amt_1')
{
var curAmt = json[i][objects];
output += '<td class="amt">' + curAmt + '</td>';
total += parseFloat(curAmt);
}
...
output += '<td>' + total + '</td>';
You can't have more than one element with the same id on a page. $("#someId") will always select at most 1 element. So, your first problem is you don't even have a list of elements. You can solve that by using class instead.
Once you resolve the id issue, the trouble you'll have is you are trying to add text as though it were a number. First, you convert text to a number in one loop, then you loop through your entire collection again and try to add the textual numbers. Just get the total during the first loop. You'll be adding numbers instead of text, and you'll only have to iterate your collection once.
Also, you don't need to iterate the keys of an object just get a property. You can just reference the property directly: json[i].amt_1
While we're at it, let's not build up the html string, but instead just create the DOM elements directly. And take advantage of $.each() to do our looping.
var total = 0;
$.each(json, function (i, item) {
var row = $('<tr>').appendTo("#details");
$("<td>").appendTo(row).addClass("amt").text(item.amt_1);
total += item.amt_1;
});
var row = $("<tr>").appendTo("#details");
$("<td>").appendTo(row).text(total);