Get row and cell value from dynamically generated table - javascript

I am trying to get the row and cell from a dynamically generated table onClick function. I am getting undefined currently.
xmlTitles = xmlDoc.getElementsByTagName("title");
document.getElementById('playlist').innerHTML = "Playlist (" + xmlTitles.length + " videos)";
document.getElementById('table').cellSpacing = "5px";
for (var i = 0; i < xmlTitles.length; i++)
{
tr = document.createElement('tr');
tr.style.height = "100px";
titles[i] = xmlDoc.getElementsByTagName("title")[i].childNodes[0].nodeValue;
image[i] = xmlDoc.getElementsByTagName("image")[i].childNodes[0].nodeValue;
filename[i] = xmlDoc.getElementsByTagName("filename")[i].childNodes[0].nodeValue;
td2 = document.createElement('td');
var _image = iPath + image[i];
td2.innerHTML = "<a href='javascript:callVideo(this);'><img src='" + _image + "'/></a>";
td2.style.verticalAlign = "top";
tr.appendChild(td2);
td1 = document.createElement('td');
var _title = titles[i];
td1.appendChild(document.createTextNode(_title));
td1.style.verticalAlign = "top";
td1.style.width = "200px";
td1.style.height = "100px";
td1.style.color = "#0000ff";
td1.style.fontFamily = "arial";
tr.appendChild(td1);
document.getElementById('table').appendChild(tr);
}
}
This is the function called:
function callVideo(x)
{
console.log("Cell index: " + x.cellIndex);
}
Thanks.

I think the issue you are having is the context of your callVideo function. When you build up the dynamic table, you create an anchor tag inside td2 and then put the event handler on the a tags href, passing in this. I would suspect, that x in callVideo is not the TD element at all, but the anchor tag (a tag) and since a tags have no cellIndex, it will be undefined. Add a console.log(x) into callVideo and establish exactly what x is. If I am correct, the x.parentNode should get you the TD tag
function callVideo(x)
{
console.log(x); //Establish what x is
console.log("Cell index: " + x.parentNode.cellIndex);
}
EDIT
In response to comment.
OK so you're having issues establishing the context of the eventHandler. I would change the way you are setting it up, as it not really best practice. An <a> is an anchor/link, and running a function on click is changing its default behaviour, which means you have it add things like javascript(void) or href="#" and return false or e.preventDefault() just to stop it from doing what is suppose to do. All not best practice. Why not just add a click handler to the img, or to the whole cell. eg (I removed the style stuff for clarity, I think that should be in CSS not Javascript too by the way)
xmlTitles = xmlDoc.getElementsByTagName("title");
document.getElementById('playlist').innerHTML = "Playlist (" + xmlTitles.length + " videos)";
document.getElementById('table').cellSpacing = "5px";
for (var i = 0; i < xmlTitles.length; i++)
{
tr = document.createElement('tr');
titles[i] = xmlDoc.getElementsByTagName("title")[i].childNodes[0].nodeValue;
image[i] = xmlDoc.getElementsByTagName("image")[i].childNodes[0].nodeValue;
filename[i] = xmlDoc.getElementsByTagName("filename")[i].childNodes[0].nodeValue;
td2 = document.createElement('td');
//change here
var imgEle = document.createElement('img')
imgEle.src = iPath + image[i];
imgEle.addEventListener('click', callVideo);
td2.appendChild(imgEle);
tr.appendChild(td2);
td1 = document.createElement('td');
var _title = titles[i];
td1.appendChild(document.createTextNode(_title));
tr.appendChild(td1);
document.getElementById('table').appendChild(tr);
}
function callVideo()
{
//'this' will be the img itself
//so this.parentNode will be the cell (TD)
console.log(this.parentNode.cellIndex);
//this.parentNode.parentNode will be the row (TR)
console.log(this.parentNode.parentNode.rowIndex);
}
OH and by the way, all the cells will return 0 as that is their index, remember Javascript indexes start from 0 (i.e. 0 is the first one, 1 is the second one etc). So to be honest, I'm not sure why you need the cellIndex, as it will always be 0 (i.e. the first cell) as you already know its in the first cell, because your code created it. Although if this is just a snippet from larger code, and you have images in other cells then it would make sense.

two changes need to make, given your dynamic generation of DOM is correct.
change ... to ..., to make it an event handler. Otherwise because the execution of the function via href is in global context, this will be effectively the global object which is window. Therefore your function will receive window as its parameter which is wrong
change the body of your callVideo function to OJay's solution
function callVideo(x)
{
console.log(x); //Establish what x is
console.log("Cell index: " + x.parentNode.cellIndex);
}

Related

Using Javascript to embed an onClick event to an HTML div

I'm trying to make an interactable and configurable grid using divs as their cells.
To first give a bit of context on this part of the code, I'm basically just repeating td's in HTML output then appending a specific amount of divs into the td's/rows (cellID is just a method for decorating the div names);
var table, row, div;
table = document.createElement('table');
for (var i=0; i < rows; i++)
{
row = document.createElement('td');
row.id = "row-" + i;
for (var j=0; j < cols; j++)
{
div = document.createElement('div');
div.id = cellID(i, j);
row.append(div);
}
table.append(row);
}
Let's say that:
-rows = 4 and -cols = 2 | The output result on the user's end would be this :
Now my current problem that I'm trying to figure out is how to make every repeated div be given the onClick() event so that an event occurs when you click on the boxes, here is what I tried to make this work :
div.addEventListener("click", null); //This part didn't work for me, though to be honest, I don't really know what to replace the null with
div.getElementById(div.id).onclick = function() { OnClick() }; (OnClick is a test method to see if it works, however this one just rejects an error, saying that "div.getElementById" is not a function, so I don't know what's up with that.)
These things I tried were all things that had been recommended throughout, but I don't know what else could make it work.
What do you think the problem may be there?
-
div.addEventListener() should work.
But you need to create valid DOM structure. Rows are tr, cells are td. You can put the div in the td, or just use the td directly.
let rows = 2,
cols = 4;
var table, row, div;
table = document.createElement('table');
for (var i = 0; i < rows; i++) {
row = document.createElement('tr');
row.id = "row-" + i;
for (var j = 0; j < cols; j++) {
let cell = document.createElement("td");
div = document.createElement('div');
div.id = cellID(i, j);
div.addEventListener("click", function() {
console.log('Clicked on', this.id);
});
div.innerText = div.id;
cell.append(div);
row.append(cell);
}
table.append(row);
}
document.body.appendChild(table);
function cellID(i, j) {
return `cell-${i}-${j}`;
}

How to add large amount of HTML using pure javascript without innerHTML

I'm trying to determine how to append a large amount of HTML to an existing element in the DOM. Due to certain constraints, I can't use innerHTML. Supposedly it's bad to use innerHTML as it doesn't treat things like an object and reloads the DOM or something. I know jquery's .append() is an option, as it supposedly does things properly, but I want to use pure javascript; I've read a few things saying jQuery shouldn't be used anymore. If there are any other libraries, or if jQuery is a valid option, then I'm fine with using it. I'm just trying to do/learn things the "right way".
Here's how I've been doing it. The function takes some info and creates a table row. This seems like a bit much to do something so simple...
function flyoutAddTicket(caseID, ticketNumber, accountName, subject, tktStatus, priority, createdDate){
//Create table row that will be inserted into the flyout table
var newtr = document.createElement("tr");
newtr.id = "sfoFlyout_Ticket_" + caseID;
newtr.className = "sfoFlyout_Ticket";
// Create elements that will be inserted into the list item
var tdOwn = document.createElement("td");
tdOwn.id = "sfoFlyout_Ticket_" + caseID + "_OwnButton";
var btnOwn = document.createElement("button");
btnOwn.className = "sfoFlyout_own sfo_button";
btnOwn.value = caseID;
btnOwn.textContent = (easterEggs.pwnButton) ? "Pwn" : "Own";
var tdTicketNumber = document.createElement("td");
tdTicketNumber.id = "sfoFlyout_Ticket_" + caseID + "_TicketNumber";
var aTicketNumber = document.createElement("a");
aTicketNumber.textContent = ticketNumber;
aTicketNumber.href = "/" + caseID;
var tdAccountName = document.createElement("td");
tdAccountName.id = "sfoFlyout_Ticket_" + caseID + "_Client";
tdAccountName.textContent = accountName;
var tdSubject = document.createElement("td");
tdSubject.id = "sfoFlyout_Ticket_" + caseID + "_Subject";
var aSubject = document.createElement("a");
aSubject.textContent = subject;
aSubject.href = "/" + caseID;
var tdStatus = document.createElement("td");
tdStatus.id = "sfoFlyout_Ticket_" + caseID + "_Status";
tdStatus.textContent = tktStatus;
var tdPriority = document.createElement("td");
tdPriority.id = "sfoFlyout_Ticket_" + caseID + "_Priority";
tdPriority.className = "sfoFlyout_Ticket_Priority";
tdPriority.textContent = priority;
// Append elements to table row
if (sfoOptions.ownButton){ newtr.appendChild(tdOwn); }
tdOwn.appendChild(btnOwn);
newtr.appendChild(tdTicketNumber);
tdTicketNumber.appendChild(aTicketNumber);
newtr.appendChild(tdAccountName);
newtr.appendChild(tdSubject);
tdSubject.appendChild(aSubject);
newtr.appendChild(tdStatus);
newtr.appendChild(tdPriority);
// Assign user preferred colors/borders
for (var pref in preferences.clients){
// Set border thickness/colors
if (preferences.clients[pref].name == "border"){
newtr.style.borderBottomWidth = sfoOptions.borderThickness + "px";
newtr.style.borderColor = preferences.clients[pref].color;
}
// Set row colors
if (preferences.clients[pref].name == accountName){
newtr.style.backgroundColor = preferences.clients[pref].color;
}
}
//Add list item to the flyout
flyoutTable.appendChild(newtr);
}
you can push the created elements into a list them loop through the list and then inside the for loop
document.getElementById('yourElement').appendChild(elementYouCreated)
or use appendChild() on your created elements
elementYouCreated.appendChild(itsChildYouCreated)

how to set onclick attribute in a loop

I am building a table with text in the first column and buttons that do stuff in the second column. Here is the complete .js file:
var table = document.createElement("table");
var tableBody = document.createElement("tbody");
for(i = 0; i < array.length; i++) {
var row = table.insertRow(i);
var cell = row.insertCell(0);
cell.innerHTML = text[i];
var cell = row.insertCell(1);
var cellElement = document.createElement("input");
cellElement.setAttribute("id", ID[i]);
cellElement.setAttribute("type", "button");
cellElement.setAttribute("value", "button");
/////cellElement.onclick =
/////function(){ doThisThing(i,ID[i]); } );
cell.appendChild(cellElement);
row.appendChild(cell);
}
table.appendChild(tableBody);
document.body.appendChild(table);
Everything works except for the cellEllement.onclick = function(){}; The onlick() function does not set. I have tried variations on this:
cellElement.setAttribute("onclick",doThisThing(i,ID[i]));
How to I set the button onclick attribute when looping through to create a table?
You're using a reference to the i variable inside your function which will continue to change with the loop, and won't hold the value of i that it has when you go through that iteration of the loop. You need to hold on to the current value of i, probably by wrapping your callback in another function:
cellElement.onclick = (function(currI) {
return function() { doThisThing(currI, ID[currI]); };
})(i);
You could also use bind to make things simpler:
cellElement.onclick = doThisThing.bind(null, i, ID[i]);

Adding ledger totals in multiple TDs

This code generates a ledger. I narrowed it down to the minimum. By clicking a plus sign it adds an additional row to the ledger.
I'm looking to add each total of the variable newAmount and locate its updated total in a TD to the right of each row. I created newAmount.id = "mainAmount"; to create unique IDs thinking this would help.
var mainNumber = 0;
function addElement()
{
//add a number for each row
mainNumber++;
//create each row, id each slot, and add it where it goes
newDiv = document.createElement("div");
newDiv.id = "main";
newTable = document.createElement("table");
newTable.id = "mainTable";
newDiv.appendChild(newTable);
newTr = document.createElement("tr")
newTr.id = (mainNumber);
newTr.className = "mainRow";
newTable.appendChild(newTr);
newAmount = document.createElement("td");
newAmount.id = "mainAmount";
newAmount.className = (mainNumber);
newPlus = document.createElement("td");
newPlus.id = "mainPlus";
newTotalTable = document.createElement("table");
newDiv.appendChild(newTotalTable);
newTotalTable.id = "mainTotalTable";
newTotalTr = document.createElement("tr");
newTotalTable.appendChild(newTotalTr);
newTotalTr.id = "mainTotalTr";
newTotalTd = document.createElement("td");
newTotalTd.id = "mainTotalTd" + (mainNumber);
newTr.appendChild(newAmount);
newTotalTr.appendChild(newTotalTd);
//whats default inside of each slot
newAmount.innerHTML = '<form name="formAmount"><textarea name="textAmount" size="25" onfocus="wait();" id="amount' + (mainNumber) + '">0</textarea>';
newTr.appendChild(newPlus);
//click this to add a row
newPlus.innerHTML = '<img src="images/plus.png">';
// add the newly created element and it's content into the DOM
my_div = document.getElementById("mainAnchor");
document.body.insertBefore(newDiv, my_div);
}
//doesn't work...trying to hover over any row and show var idName in console
function trHover(){
$('tr').hover(function() {
var idName = $('tr'+'#'+(mainNumber)).attr('id');
console.log(idName);
});
}
//when you focus on amount box, this is activated, which adds attribute onblur and stars addTotal
function wait(){
var blurred = $(this).attr("onblur");
blurred = addTotal();
}
//adds total and displays it in td to the right
function addTotal(){
var y = 1;
var sum = 0;
var input;
while( ( input = document.getElementById( 'amount'+y ) ) ) {
sum += parseInt( input.value );
++y;
console.log(sum);
$("#mainTotalTd1").text(sum);
}
}
Rather than adding a single row, it looks like clicking the plus sign adds a div and two tables, so I'm not sure what you are going for there. I can fix the hover function, though:
$('tr').hover(function() {
var idName = $(this).attr('id'); // 'this' is the element being hovered
console.log(idName);
});

JavaScript/DOM - Give a newly created element an ID

How can I apply an element ID to a newly created element through JavaScript DOM?
The code I have written creates a table which is triggered from a button.
I need to apply a unique ID to this table so it can be styled differently to others which appear on my site.
Here is a sample of my code:
var tab = document.createElement("ViewShoppingCart");
document.getElementById("shopping_list").appendChild(tab);
var tbdy = document.createElement("tbody");
tab.id = "new_cart";
tab.appendChild(tbdy);
new_cart = true;
var total = 0;
for (var a = 0; a <= nameArray.length-1; a++) {
var tr = document.createElement("tr");
tbdy.appendChild(tr);
var td = document.createElement("td");
td.appendChild(document.createTextNode("x " + quantityArray[a]));
tr.appendChild(td);
var td2 = document.createElement("td");
td2.appendChild(document.createTextNode(nameArray[a]));
tr.appendChild(td2);
var td3 = document.createElement("td");
td3.appendChild(document.createTextNode(sumArray[a]));
tr.appendChild(td3);
}
Try
var tbdy = document.createElement("tbody");
tbdy.id = "newtbodyid";
tab.id = "new_cart";
tab.appendChild(tbdy);
new_cart = true;
For applying styles consider using class selectors, you may not need IDs at all.
Note that if you want to create valid HTML you can't have duplicated IDs that significantly lessens value for CSS styles, especially for table data.

Categories

Resources