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

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)

Related

Get row and cell value from dynamically generated table

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

set multiple sliders onchange functions with changin variables

I have a loop with changing parameters wich I'd like to use in a oninput function of the sliders I'm creating within that loop, but I can't get it to work. Here's a simplified version of my script:
for (var con in dict) {
var div = document.getElementById("content");
var conDiv = document.createElement("div");
conDiv.innerHTML = "<b>" + con + ":</b><br>";
var effectID = dict[con].effect_id;
for (var param in dict[con].params) {
var inp,span = document.createElement("span");
span.innerHTML = " " + param + " ";
conDiv.appendChild(span);
inp = document.createElement("input");
inp.type = "range";
inp.min = vars[effectID][param].min;
inp.max = vars[effectID][param].max;
inp.value = dict[con].params[param];
inp.oninput = function(con,param,val) {
setParam(con,param,val);
}(con,param,this.value);
conDiv.appendChild(inp);
}
div.appendChild(conDiv);
}
What's wrong with my code?
edit: My goal: I have a set of audio effects that I want to change. Every container (con) controls an effect node via multiple parameters. All those parameters have different min- and max-values and an actual value they have right now. Via the sliders I want to be able to call a function that changes the parameters of an container. Therefore, every slider should control one effect parameter.
That's because the callback is called after the loop finish, so your variables have changed.
A usual trick is to use an immediately called function whose scope can store your variable values :
for (var con in dict) {
(function(con) { // <= creates a scope and a new con variable
var div = document.getElementById("content");
var conDiv = document.createElement("div");
conDiv.innerHTML = "<b>" + con + ":</b><br>";
var effectID = dict[con].effect_id;
for (var param in dict[con].params) {
(function(param){
var inp,span = document.createElement("span");
span.innerHTML = " " + param + " ";
conDiv.appendChild(span);
inp = document.createElement("input");
inp.type = "range";
inp.min = vars[effectID][param].min;
inp.max = vars[effectID][param].max;
inp.value = dict[con].params[param];
inp.oninput = function() {
setParam(con,param,inp.value);
};
conDiv.appendChild(inp);
})(param);
}
div.appendChild(conDiv);
})(con);
}

DOM Add Table Row Where I Want It [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to do insert After() in JavaScript without using a library?
Currently this script adds a row at the bottom of the table. How do I tell it to add it after a particular row? At the top of the table?
<script>
var i = 1;
function changeIt() {
var tr = document.createElement('tr');
var td = tr.appendChild(document.createElement('td'));
td.style.valign = 'middle';
var span = td.appendChild(document.createElement('span'));
span.style.fontWeight = 'bold';
span.appendChild(document.createTextNode('URL ' + i));
td = tr.appendChild(document.createElement('td'));
var input = td.appendChild(document.createElement('input'));
input.name = 'url' + ++i;
input.type = 'text';
input.size = '40'
document.getElementById('myTable').tBodies[0].appendChild(tr);
}
</script>
I've been searching Google to learn, but I keep coming across jQuery, innerhtml, and insertrow answers.
You're looking for node.insertBefore() https://developer.mozilla.org/en-US/docs/DOM/Node.insertBefore
var i = 1;
function changeIt() {
var tr = document.createElement('tr');
var td = tr.appendChild(document.createElement('td'));
td.style.valign = 'middle';
var span = td.appendChild(document.createElement('span'));
span.style.fontWeight = 'bold';
span.appendChild(document.createTextNode('URL ' + i));
td = tr.appendChild(document.createElement('td'));
var input = td.appendChild(document.createElement('input'));
input.name = 'url' + ++i;
input.type = 'text';
input.size = '40'
var node = document.getElementById('myTable').tBodies[0];
node.insertBefore(tr, node.firstChild);
}
To add to a specific position you will need to know the index in the .children. Otherwise some key identifier (class name, attribute, or ID), something you can pass into a getBy or QSA.

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