Getting value from cell within dynamically generated table - javascript

I have a table that is dynamically generated via JavaScript based on data from an SQL query. The first cell contains a button that should retrieve the value in the 2nd cell within that row onclick. For some reason, the jQuery onclick event is not firing. No errors are being thrown in the browser.
HTML
...
for (var i=0; i<queryReturned.Result.length; i++) {
var tableRow = document.createElement("tr");
var cell = document.createElement("td");
var button = document.createElement("button"); //Button gets added here
button.type = "button";
button.value = "Remove Alert";
button.className = "buttonSelect"
cell.appendChild(button);
tableRow.appendChild(cell);
//This loop creates the rest of the cells and fills in their data
for (var j=0; j<Object.keys(queryReturned.Result[i]).length; j++) {
var cell2 = document.createElement("td");
var cellText = document.createTextNode(Object.values(queryReturned.Result[i])[j]);
cell2.appendChild(cellText);
tableRow.appendChild(cell2);
}
tableBody.appendChild(tableRow);
}
table.appendChild(tableBody);
table.setAttribute("border", "2");
body.appendChild(table);
...
jQuery
$(document).ready(function(){
$(".buttonSelect").on('click',function(){
var currentRow=$(this).closest("tr");
var col2=currentRow.find("td:eq(1)").html();
alert(col2); //alert for now to test if we grabbed the data
});
});

Reword your event handler function like so:
$(document).on('click', '.buttonSelect', function(){ ... });
so it will work for dynamically added elements as well.
Let us know how it goes!

Firstly the main problem is that you need to use a delegated event handler to attach the click event to the button element.
Also, you're using an odd mix of JS and jQuery. You can massively simplify the table creation logic. Too. Try this:
$(function() {
var $table = $('<table />').appendTo('body'); // this wasn't in your code example, but should look like this
queryReturned.Result.forEach(function(result) {
var $tr = $("<tr />").appendTo($table);
var $td = $("<td />").appendTo($tr);
$('<button class="buttonSelect">Remove Alert</button>').appendTo($td);
for (var j = 0; j < Object.keys(result).length; j++) {
$('<td />').text(result[j]).appendTo($tr);
}
}
$(document).on('click', '.buttonSelect', function() {
var currentRow = $(this).closest("tr");
var col2 = currentRow.find("td:eq(1)").html();
alert(col2);
});
});

Related

Handle with dynamically made elements in Javascript

Is there a way to handle elements made dynamically on loading the page?
for example, I have a code below.
function makeAFrame(index)
{
var padding=document.createElement('p');
var frameDiv=document.createElement('div');
frameDiv.id="frame";
frameDiv.className="frame";
var placeButton=document.createElement('input');
placeButton.id="bButton"+index;
placeButton.className="bButton";
placeButton.value="aaa";
placeButton.type="button";
var buyButton=document.createElement('input');
buyButton.id="aButton"+index;
buyButton.className="aButton";
buyButton.value="Buy It Now";
buyButton.type="button";
var table=document.createElement('table');
table.setAttribute('cellpadding','3');
table.setAttribute('width','100%');
var col1=["a", "b", "c","d","e:", "f"];
var row;
var text;
var cell;
var i=0;
for(i=0;i<6;i++)
{
row = table.insertRow(i);
text = document.createTextNode(col1[i]);
cell = row.insertCell(0);
cell.setAttribute('align','right');
cell.setAttribute('width','30%');
cell.appendChild(text);
text = document.createTextNode(hey[index][i]);
cell = row.insertCell(1);
cell.setAttribute('align','left');
cell.appendChild(text);
}
for(i=6;i<8;i++)
{
row = table.insertRow(i);
text = document.createTextNode("");
cell = row.insertCell(0);
cell.setAttribute('align','right');
cell.setAttribute('width','30%');
cell.appendChild(text);
if(i==7)
{
cell = row.insertCell(1);
cell.setAttribute('align','left');
cell.appendChild(placeButton);
cell.appendChild(buyButton);
break;
}
else if(i==6)
text = document.createTextNode(remaining);
cell = row.insertCell(1);
cell.setAttribute('align','left');
cell.appendChild(text);
}
var body=document.getElementById('body');
frameDiv.appendChild(table);
body.appendChild(frameDiv);
body.appendChild(padding);
}
Once the function has been run which means after all elements are shown in the page. What I would like to do is when I click a 'aButton0'(aButton+index) a input box shows up. I make all button codes with index so they are accessible but I have no idea how to access after they are shown in the page.
Why dont you just add an onclick handler to your button when you create it, just add
placeButton.setAttribute("onclick", "showPopUp();");
Then you can react to your specific button within in the showPopUp function.

How can I reference an element after I have appended it using javascript not jquery

I am doing some basic javascripting and am creating a 3 column table created by javascript sourced from an xml. The table is created by appending all the data in rows via javascript.
The first column has an input checkbox, created via javascript, that if ticked fetches a price from the third column on that row and adds all the prices of the rows selected to give a price total.
The problem I am having is I don't seem to be able to reference the appended information to obtain the information in the related price column (third column).
I have attached both the function I am using to create the table which is working and the function I am using to try and add it up which isnt working.
I found the following two articles Getting access to a jquery element that was just appended to the DOM and How do I refer to an appended item in jQuery? but I am using only javascript not jquery and would like a javascript only solution if possible.
Can you help? - its just the calculateBill function that isn't working as expected.
Thank you in advance
function addSection() {
var section = xmlDoc.getElementsByTagName("section");
for (i=0; i < section.length; i++) {
var sectionName = section[i].getAttribute("name");
var td = document.createElement("td");
td.setAttribute("colspan", "3");
td.setAttribute("class","level");
td.appendChild(document.createTextNode(sectionName));
var tr = document.createElement("tr");
tr.appendChild(td);
tbody.appendChild(tr);
var server = section.item(i).getElementsByTagName("server");
for (j=0; j < server.length; j++) {
var createTR = document.createElement("tr");
var createTD = document.createElement("td");
var createInput = document.createElement("input");
createInput.setAttribute("type", "checkbox");
createInput.setAttribute("id", "checkInput");
createTD.appendChild(createInput);
createTR.appendChild(createTD);
var item = server[j].getElementsByTagName("item")[0].innerHTML;
var createTD2 = document.createElement("td");
var createText = document.createTextNode(item);
createTD2.appendChild(createText);
createTR.appendChild(createTD2);
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
}
}
}
onload = addSection();
function calculateBill() {
var finalBill = 0.0;
var checkBox = document.getElementById("checkInput");
for (i=0; i < checkBox.length; i++) {
if (checkBox[i].checked) {
var parentTR = checkBox[i].parentNode;
var priceTD = parentTR.getElementsByTagName('td')[2];
finalBill += parseFloat(priceTD.firstChild.data);
}
}
return Math.round(finalBill*100.0)/100.0;
}
var button = document.getElementById("button");
button.onClick=document.forms[0].textTotal.value=calculateBill();
When you do x.appendChild(y), y is the DOM node that you are appending. You can reference it via javascript either before or after appending it. You don't have to find it again if you just hang on to the DOM reference.
So, in this piece of code:
var createInput = document.createElement("input");
createInput.setAttribute("type", "checkbox");
createInput.setAttribute("id", "checkInput");
createTD.appendChild(createInput);
createInput is the input element. You can reference it with javascript at any time, either before or after you've inserted it in the DOM.
In this piece of code:
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
You're creating a <td> element and putting a price into it. createTD3 is that particular <td> element.
If you want to be able to find that element sometime in the future long after the block of code has run, then I'd suggest you give it an identifying id or class name such that you can use some sort of DOM query to find it again. For example, you could put a class name on it "price" and then be able to find it again later:
var price = server[j].getElementsByTagName("price")[0].innerHTML;
var createTD3 = document.createElement("td");
createTD3.className = "price";
var createText2 = document.createTextNode("£" + price);
createTD3.appendChild(createText2);
createTR.appendChild(createTD3);
tbody.appendChild(createTR);
Then, you could find all the price elements again with:
tbody.querySelectorAll(".price");
Assuming tbody is the table where you put all these elements (since that's what you're using in your enclosed code). If the table itself had an id on it like id="mainData", then you could simply use
document.querySelectorAll("#mainData .price")
to get all the price elements.
FYI, here's a handy function that goes up the DOM tree starting from any node and finds the first node that is of a particular tag type:
function findParent(node, tag) {
tag = tag.upperCase();
while (node && node.tagName !== tag) {
node = node.parentNode;
}
return node;
}
// example usage:
var row, priceElement, price;
var checkboxes = document.querySelectorAll(".checkInput");
for (var i = 0; i < checkboxes.length; i++) {
// go up to the parent chain to find out row
row = findParent(checkboxes[i], "tr");
// look in this row for the price
priceElement = row.querySelectorAll(".price")[0];
// parse the price out of the price element
price = parseFloat(priceElement.innerHTML.replace(/^[^\d\.]+/, ""));
// do something here with the price
}

looping javascript didn't work

I'm trying to get data from app engine datastore using javascript and json. it's also allowed jsonp service, here the javascript code:
$.getJSON("http://1.handy-post-402.appspot.com/show?callback=?", function(json) {
for (var i = 0; i < json.length; i++) {
var map = json[i].propertyMap;
var content = map.isi;
var user = map.No_HP;
var date = map.tanggal;
$('#date').text(date);
$('#nohp').text(user);
$('#content').text(content);
}
});
you can also check it here: http://jsfiddle.net/YYTkK/7/
unfortunately, it just retrieve 1 latest data from the datastore. am I doing something wrong with this code?
thanks in advance.
You're not appending elements, but simply changing the value of the same 3 elements in question three times. So you simply overwrite the value you put into it the time before. The easiest way to solve this is to designate the existing tr as a .template and clone it in your loop, make the necessary changes (filling in the values) and then appending it.
Fixing some other unclear things this gives the following
$.getJSON("http://1.handy-post-402.appspot.com/show?callback=?", function(records) {
for (var i = 0; i < records.length; i++) {
//Clone the row/unit which we will be using for each record (the class should refer to the type of item it /actually/ is)
row = $(".row.template").clone();
//The template class is hidden, so remove the class from the row/unit
row.removeClass("template");
var map = records[i].propertyMap;
var content = map.isi;
var user = map.No_HP;
var date = map.tanggal;
//Make the required changes (find looks for the element inside var row)
row.find('.date').text(date);
row.find('.nohp').text(user);
row.find('.content').text(content);
//Append it to the parent element which contains the rows/units
$("tbody").append(row);
}
});
See functional demo: http://jsfiddle.net/YYTkK/13/
You must append a new row in the table in every loop. Here's the working fiddle.
fiddle
$.getJSON("http://1.handy-post-402.appspot.com/show?callback=?", function(json) {
for (var i = 0; i < json.length; i++) {
var map = json[i].propertyMap;
var content = map.isi;
var user = map.No_HP;
var date = map.tanggal;
var row = '<tr><td>'+date+'</td><td>'+user+'</td><td>'+content+'</td></tr>';
$('#valuetable').append(row);
}
});
what you have to do is create dynamic "tr" s and append to tbody and use thead for header and separate the body using tbody and create tr s on each iteration and after the loop append that tr to tbody. that will do the job, as you do now it will override the values at each iteration.
#chamweer answer is correct you have to create a new tr with td's dynamically
like this:
http://jsfiddle.net/YYTkK/14/
Because you're overriding the same td's over and over again.
$.getJSON("http://1.handy-post-402.appspot.com/show?callback=?", function(json) {
for (var i = 0; i < json.length; i++) {
var map = json[i].propertyMap;
var content = map.isi;
var user = map.No_HP;
var date = map.tanggal;
// create a temporary tr
var tr = $("<tr />");
// append to the tr the td's with their values
tr.append($("<td />").text(date), $("<td />").text(user),
$('<td />').text(content));
// finally append the new tr to the table's tbody
$("#js-tbody").append(tr);
}
});

Trigger click event on click of other element in a loop

I have a requirement where I have to fire click event on table header on click of other table header (2 different tables), but trigger is not fired on the table when in a loop. Although if I hardcode and bind the trigger to individual element, it works.
Currently, the JS looks like something like this:
var outsideHeaders = $("#header th");
var tableHeaders = $(".dataTable th");
for(var cnt = 0; cnt< outsideHeaders.length; cnt++)
{
$(outsideHeaders[cnt]).bind('click',function(){
$(tableHeaders[cnt]).trigger('click');
});
}
Please provide solution for this!
Updated:
This is how my code looks now:
var outsideHeaders = $("#header th");
var tableHeaders = $(".dataTable th");
for(var cnt = 0; cnt< outsideHeaders.length; cnt++)
{
(function(headerCnt){
$(outsideHeaders[headerCnt]).bind('click',function(){
$(tableHeaders[headerCnt]).trigger('click');
});
})(cnt);
}
The value of cnt inside the click event handler function is going to be equal to its last value in the for loop (in this case, whatever header.length was when the code executed) due to the way scoping in JavaScript works. You need to use a closure so that it maintains its value for that specific iteration:
$(document).ready(function() {
var outsideHeaders = $("#header th");
var tableHeaders = $(".dataTable th");
for(var cnt = 0; cnt < outsideHeaders.length; cnt++)
{
(function(headerCount) {
$(outsideHeaders[headerCount]).bind('click',function(){
$(tableHeaders[headerCount]).trigger('click');
});
})(cnt);
}
});
Note that I've wrapped the code in a $(document).ready() call. This will ensure that the elements exist when you try to select them.
var $outsideHeaders = $("#header th"),
$tableHeaders = $(".dataTable th");
$outsideHeaders.on('click', function(){
var i = $outsideHeaders.index(this);
$tableHeaders.eq(i).trigger('click');
});
No need in making iteration. I guess this could be the right way here:
outsideHeaders.on("click", function() {
var cnt = outsideHeaders.index(this);
tableHeaders.eq(cnt).trigger("click");
});
You simply bind click event to all outsideHeaders and trigger click event of the corresponding element of tableHeaders based on the index.

DOM onmouseover not appearing

I'm trying to insert an onmouseover when creating new rows within my table however it's not appearing. Am I missing something stupid?
var row = document.createElement("TR");
row.id = i;
row.onmouseover = hover(i);
var td1 = document.createElement("TD");
row.appendChild(td1);
tbody.appendChild(row);
The variable 'i' is the current number in the loop. The ID of the row appears fine, but not the onmouseover.
Use an anonymous function to create a closure for the value of i, and make sure you're setting a function to onmouseover, rather than the result of calling a function:
var row = document.createElement("TR");
(function (i) {
row.onmouseover = function () { hover(i) };
})(row.id);
var td1 = document.createElement("TD");
row.appendChild(td1);
tbody.appendChild(row);
Taking a proper look at your code, it appears that you're not actually setting the id attribute of the TR element. However, you might want to avoid that entirely and use this context inside the hover function:
var row = document.createElement("TR");
row.onmouseover = hover;
var td1 = document.createElement("TD");
row.appendChild(td1);
tbody.appendChild(row);
function hover() {
alert(this.rowIndex); // <-- `this` refers to the row element
}
You are assigning the result of the function to the event.
Needs to be something like
row.onmouseover=function(){hover(this);}
And it is better to use this since you have the DOM object and do not have to look up anything.
function hover( row ){
row.style.color = "red";
}
If you still what to go the i way, you need to change your id so it is valid. Ids can not start with a number.
var row = document.createElement("TR");
row.id = "row_i";
row.onmouseover = function(){ hover(this.id); }
var td1 = document.createElement("TD");
row.appendChild(td1);
tbody.appendChild(row);
Maybe try:
row.onmouseover = function() { hover(i); };

Categories