Why can't I add to innerHTML? [duplicate] - javascript

document.getElementById("outputDiv").innerHTML = "";
document.getElementById("outputDiv").innerHTML += "<table border=1 width=100%><tr>";
for(j=1;j<=10;j++)
{
document.getElementById("outputDiv").innerHTML += "<td align=center>"+String.fromCharCode(j+64)+"</td>";
}
document.getElementById("outputDiv").innerHTML += "</tr></table>";
I want to draw a table using Javascript.
So I wrote the code like above.
I think it draw one row that has 10 columns, but it doesn't work.
Anyone know about this problem???

I ran into this problem years ago, too.
The problem is that when you use the innerHTML property to add HTML, after each update, the underlying engine will close unclosed tag (and fix other bad HTML) for you. So after the second line, the <table> and <tr> tags are automatically closed and all content after that will just be written outside the table.
Method 1
(The easy way)
Use a string to store the HTML for the whole table and update it all at once.
var HTML = "<table border=1 width=100%><tr>";
for(j=1;j<=10;j++)
{
HTML += "<td align=center>"+String.fromCharCode(j+64)+"</td>";
}
HTML += "</tr></table>";
document.getElementById("outputDiv").innerHTML = HTML;
​
Fiddle
Method 2
(The better way)
Use DOM functions
var table = document.createElement('table');
table.setAttribute('border','1');
table.setAttribute('width','100%')
var row = table.insertRow(0);
for(j=1; j<=10; j++){
var text = document.createTextNode(String.fromCharCode(j+64));
var cell = row.insertCell(j-1);
cell.setAttribute('align','center')
cell.appendChild(text);
}
document.getElementById("outputDiv").appendChild(table);
Fiddle
Method 2 enhanced
(The yet better way)
Use CSS instead of HTML attributes. The latter is generally depreciated as of latest specs.
A great resource to start learning CSS is the Mozilla Developer Network
Fiddle
Method 3
(The long way, but the best in the long-run)
Use jQuery.
$('<table>').append('<tr>').appendTo('#outputDiv');
for(j=1; j<=10; j++)
$('<td>').text(String.fromCharCode(j+64)).appendTo('tr');
Fiddle

I think the main problem is that your attributes are not quoted.
But it's almost always a bad idea to repeatedly update the content of a dom element in a loop—each time you update dom content it causes some internal work to be done by the browser to make sure the page layout is current.
I would build the html string up locally, then make one final update when done. (and of course make sure your attributes are quoted)
document.getElementById("outputDiv").innerHTML = "";
var newTable = "<table border='1' width='100%'><tr>";
for(j = 1; j <= 10; j++) { //opening braces should always be on the same line in JS
newTable += "<td align='center'>" + String.fromCharCode(j+64) + "</td>";
}
newTable += "</tr></table>";
document.getElementById("outputDiv").innerHTML = newTable;

Related

Javascript autocloses HTML tags?

Why do these two functions give different results?
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
var register = [
{att1: 1, att2: 2, att3: 3},
{att1: 4, att2: 5, att3: 6},
{att1: 7, att2: 8, att3: 9}
];
//table1.innerHTML = "";
//table2.innerHTML = "";
function drawTable1() {
for (var i = 0; i < register.length; i++) {
table1.innerHTML += "<tr><td>" + register[i].att1 + "</td><td>" + register[i].att2 + "</td><td>" + register[i].att3 + "</td></tr>";
}
}
function drawTable2() {
for (var i = 0; i < register.length; i++) {
table2.innerHTML += "<tr>";
table2.innerHTML += "<td>" + register[i].att1 + "</td>";
table2.innerHTML += "<td>" + register[i].att2 + "</td>";
table2.innerHTML += "<td>" + register[i].att3 + "</td>";
table2.innerHTML += "</tr>";
}
}
drawTable1();
drawTable2();
table {
display: inline;
}
<body>
<table>
<thead>
<tr>
<th>Att1</th>
<th>Att2</th>
<th>Att3</th>
</tr>
</thead>
<tbody id="table1">
</tbody>
</table>
<table>
<thead>
<tr>
<th>Att1</th>
<th>Att2</th>
<th>Att3</th>
</tr>
</thead>
<tbody id="table2">
</tbody>
</table>
</body>
I'm just beginning with js, and I've noticed this thing. From a logical point of view i see no differences between the two functions, the second has just been broken up to make the code easier to read. It should simply be adding strings to a string, but it seems like at every operation the opened tags get closed by the program, resulting in a multitude of rows.
Why is this? How is this useful?
innerHTML isn't actually a string. It's an interface to the DOM (the elements on the page); reading from it generates a string version of what's currently there, and assigning a value to it modifies the tree.
It's impossible to have an unclosed <tr> element in the DOM -- when you perform an operation like table1.innerHTML += "<tr>", the browser sees the unclosed <tr> tag as invalid HTML and has to repair it by inserting a closing </tr>. When you later access innerHTML to perform another modification, you see the "repaired" version, not the value you initially assigned.
The easiest fix will be to build the entire table as a string, then assign to innerHTML all at once, e.g.
var html = "";
for (...) {
html += "<tr>";
html += "<td>example</td>";
html += "</tr>";
}
table1.innerHTML = html;
You may also want to investigate Javascript DOM methods to create HTML elements (like document.createElement()) as an alternative -- innerHTML is a clumsy interface.
Well the innerHTML content is — as the name implies — HTML and HTML is not just a string. I assume you know that browsers build a DOM out of it. Basically a tree out of nodes that know their tag, attributes, children etc.
Now you need this DOM to render anything. Sure, it is nearly impossible to get invalid html as non-html can just be interpreted as a mere string (which is valid html). However, the browser tries to fullfill the html standard as much as possible. Therefore it also generates missing end tags in order to produce well-formed html. (even when it is not in the html, he will implicitely generate them for the DOM and in some browsers you can see that in the HTML provided in the dev console).
So now you add a random <tr> attribute to your html like this table2.innerHTML += "<tr>". This would produce not-well-formed html. Therefore it should generate the missing end tag. Whether that is done while running the js-code or afterwards when refreshing the DOM, I don't know, but generally it helps generate well-formed HTML.
I'm sure you know how to circumvent that problem, but anyways: Instead of using an temporary string, you might want to look at document.createElement(). This is generally used to generate well-formed html in a non-confusing and safe (as in "something unexpected like above doesn't happen safe") way.

Cannot pass array parameter (building out html with string) - Unexpected identifier

I have modified my previous code to allow for a data array to be passed to a different function. Everything is working until I add this data array.
Currently what works (old version) is only passing the this operator and an ID.
Below in my code you will see that I build out the HTML along with a table and pass the html to be appended at a later time.
You can see that I am building a table with a delete button. It all works well, except now that I am passing the data array it is telling me "Unexpected identifier"
I have tested it with passing getDeleteItems(this,ID,ID) and it works fine
but getDeleteItems(this,ID,data) does not.
Below is my code, and you can see I am passing an array (that works throughout my code and other functions (including this one already!))
I am just stuck now and can't seem to see past this, maybe some fresh eyes can help!
Thanks!
function mouseOverTable(ID,parent,data)
{
// ID is in the first column (0)
// Type is in the second column (1)
// Title is in the third column (2)
// popup_ItemClicked()
var family = findFamily(ID,parent,data)
var sHTML = "";
sHTML += "<table class="+"table table-hover id='relationshipTable'"+">";
sHTML += "<thead>";
sHTML += "<tr>";
sHTML += "<th>"+"Select Item"+"</th>";
sHTML += "<th>"+"ID"+"</th>";
sHTML += "<th>"+"Content Name"+"</th>";
sHTML += "<th>"+"Type"+"</th>";
sHTML += "<th>"+"Status"+"</th>";
sHTML += "<th>"+"Date"+"</th>";
sHTML += "</tr>";
sHTML += "</thead>";
sHTML += "<tbody>";
//displays if it's a article.. blog ... etc..
for(var i = 0; i<family.length;i++)
{
sHTML += "<tr id='relationshipRow"+family[i].ID+"'>";
sHTML += "<td><input type = 'checkbox' value = '"+family[i].ID+"'></input></td>";
sHTML += "<td>"+family[i].ID+"</td>";
sHTML += "<td>"+family[i].Title+"</td>";
//shows the date that the contentitem was created
sHTML += "<td>" + family[i].Type +"</td>";
sHTML += "<td>" + family[i].Status +"</td>";
sHTML += "<td>" + (family[i].Date) +"</td>";
sHTML += "</tr>";
}
sHTML += "</tbody>";
sHTML += "</table>";
//console.log(data)
sHTML += "<input type = 'Button' id ='DeleteItems' value = 'Delete Selected' onclick='javascript: getDeleteItems(this,";
sHTML += ID;
sHTML += ",";
sHTML += data;
sHTML += ");'></input>";
return sHTML;
}
I just looked at console and the element tabs in chrome: it looks like for some reason it is parsing the object as such
onclick="javascript: getDeleteItems(this,791,[object Object],[object Object],[object Object],.... and this goes on...
Your error in the onclick="javascript: getDeleteItems
the third parameter expected to be an array you missed {} for the array objects.
So you must call getDeleteItems function like this
onclick="javascript: getDeleteItems(this,791,{[object Object],[object Object],[object Object]})"
As #Fatehi mentioned, the following lines are giving the error
sHTML += "<input type = 'Button' id ='DeleteItems' value = 'Delete Selected' onclick='javascript: getDeleteItems(this,";
sHTML += ID;
sHTML += ",";
sHTML += data;
sHTML += ");'></input>";
I believe that adding the curly braces wont fix your issue since that data variable is a parameter of the function and his value it's not global and the scope when you send it to the DOM is for global variables. You should better use data attributes for each value and then you could access them like this:
<input data-test="test" onclick="console.log(this.attributes['data-test'].value)">
So I figured out this puzzle. I had the following functions 1) that called mouseover, the mouseover function, then the delete function. Before I was creating a delete button in mouseover(and I still am). However I made mouseover return 2 items now, one that returns the html for the table and the other that returns a tableid. I also removed the findfamily function in mouseover and moved it up to where it was being called from, then passed that as the data.
functionThatCalledMouseOver(ID,parent,data){
// below have variables defining row family =findparent etc...
row.child(mouseOverTable(ID,parent,findParent)[0]).show();
//now create onclick even passing fullData
$('#'+DeleteItems).on('click',function(){
getDeleteItems(this,ID,data);
});
}
My ultimate goal was the following: I had some sharepoint list items I was deleting from a table. Usually when I create charts tables etc, I will do a call and store all data locally in an array. The array is what created the table I was making. So in theory after the table data is deleted from sharepoint, it is still in my local array.
The problem with this was that when I removed the elements (visually showing they were deleted), it I hid the children of the parent in the main table I created, then clicked to show it again, it would show the deleted items since it was not server information and just a local array.
For future people reading this, I tried my original method with turning the object into a JSON string, then using the escape function. So... escape(JSON.stringify(data)).. this got passed to the delete function. This does work for appearances only. Once decoded on the getDeleteItems function it is separate data from the original data I was trying to delete. So in my case this wouldn't work.
however, moving everything to the function that originally called the mouseover was the way to go. It allowed me to get to the object I needed to remove items from.

Adding color to particular cell in table by its id

function grid(rows, cols) {
var table = "<table id = \"myTable\">";
var size = (1 / rows * 525) + "px";
for (i=0; i<rows; i++) {
table += "<tr>";
for (j=0; j<cols; j++) {
var ID = i+','+j;
table += "<td id = \"ID\" >"+"</td>";
}
table += "</tr>";
}
table += "</table>";
var ID2 = randomFunction(rows, cols);
alert(ID2);
document.ID2.style.color = "red";
//document.getElementById(ID2).style.color = "#ff0000";
//table1.rows[1].cells[0].style.backgroundColor = "#003F87";
//id.style.backgroundColor='#003F87';
$("#container").empty().append(table);
}
I have generated table dynamically in javaScript specifying number of rows and columns. I have given id to each cell. I need to change the color of particular cell whose id is generated by random function. I tried in different ways but no solution.
One by one:
document.getElementById(ID2).style.color = "#ff0000";
won't work, because at this moment, the table is not in the dom, so document.getElementById(ID2) will return nothing.
table1.rows[1].cells[0].style.backgroundColor = "#003F87";
won't work, because table is a regular string, and strings don't have a rows property.
id.style.backgroundColor='#003F87';
won't work because id is again, a simple string. What would work is, to add the table to the dom first, using $("#container").empty().append(table);, and then do the setting of the color, using straightforward
document.getElementById(ID2).style.backgroundColor = "#ff0000";
or with jquery:
$("#"+ID2).css({backgroundColor: "#ff0000"}).
I would also recommend inserting a space ( ) in the table cells (note that your current code is incorrect, it sets the id for all the cells to the string "ID"), using
table += '<td id = "'+ID+'"> </td>';
otherwise the table could be rendered a little odd. Also id in the format 1,2 might cause problems, how about
var ID = 'td_'+i+'_'+j;
which gives you an ID like td_1_2, which won't mess up any browser.

Using a for loop within innerHTML

I want to add a box with individual boxes inside it with every age when the function is run. I tried doing it by splitting the innerHTML and using the for loop on just the agebox section so it will loop and create a new age box each time and not create a whole outerbox as well everytime like if you try loop the entire thing. I thought this would work but now it creates an age box for each loop but its placed outside the outer box and i cant figure out how to get it to loop within the outer box. If i remove the loop and just create one innerHTML then the age boxes i made manually are inside the outer box so im assuming theres a problem with the actual splitting up of the innerHTML. Thanks in advance!!
function Age(gender){
if (gender!==undefined){
el1 = document.getElementById('userdata');
el1.innerHTML += gender +"<br>";
}
el1 = document.getElementById('farespage');
el1.innerHTML += "<div id=\"outerbox\">";
for(var i=13; i<=18; i++){
el1.innerHTML +="<div class=\"agebox\" onclick=\"Relationship('"+i+"')\">"+i+"</div>";
}
el1.innerHTML += "</div><button type=\"button\" onclick=\"goback('Gender')\">back</button>";
}
You need to store the output content as a string and then append it to the DOM. Otherwise, the div will be auto-closed.
el1 = document.getElementById('farespage');
output = "<div id=\"outerbox\">"; //initialize output string
//build output string
for(var i=13; i<=18; i++){
output +="<div class=\"agebox\" onclick=\"Relationship('"+i+"')\">"+i+"</div>";
}
output += "</div><button type=\"button\" onclick=\"goback('Gender')\">back</button>";
el1.innerHTML = output; //output to DOM
View Fiddle
The line
el1.innerHTML += "<div id=\"outerbox\">";
is actually producing
<div id="outerbox"></div>
because most browsers will auto-close the HTML tags.
You should write all your HTML into a string buffer then append it with one big call; for example:
function Age(gender){
if (gender!==undefined){
el1 = document.getElementById('userdata');
el1.innerHTML += gender +"<br>";
}
el1 = document.getElementById('farespage');
// Magic begins here
var yourHTML = "";
yourHTML += "<div id=\"outerbox\">";
for(var i=13; i<=18; i++){
yourHTML +="<div class=\"agebox\" onclick=\"Relationship('"+i+"')\">"+i+"</div>";
}
yourHTML += "</div><button type=\"button\" onclick=\"goback('Gender')\">back</button>";
el1.innerHTML += yourHTML;
}
This has the added benefit of only touching the DOM once and not 7 times (which is generally a good thing).

Why can I not dynamically draw my table? How can I draw the table?

Readers,
Background:
I have an html page with a submit button on it. This button, when clicked goes to the servlet and fetches the first 10 rows of data from my database. I then get this data back to my javascript via an ajax call. That all works. I can see the data in json format in my javascript.
Problem:
After the data is returned, it goes to a method called generate the table. But the table never shows on my html page. I tried to follow this demo approach. How can I draw a table after this method is being called? The <p></p> approach in the demo didn't work in the link I provided either.
function createTable(result)
{
var length = result.jsonList.length;
var tablecontents = "";
console.log(length);
tablecontents="<table>";
for(var i = 0; i < length; i++)
{
tablecontents += "<tr>"
tablecontents += "<td>" + result.jsonList[i].Id + "</td>"
tablecontents += "</tr>"
console.log(result.jsonList[i].Id);
}
tablecontents="</table>";
document.getElementById("tablespace").innerHTML = tablecontents;
}
Okay, so the console.log part gives me the following output:
1
2
3
4
5
6
7
8
9
10
So I have the data. However, no database is being drawn on my htmlpage. Here is the relevant HTML code:
<body>
<form id = "submitTable" method="post">
<center><input id="getTable" type="button" value="Table"></center>
<div id="tablespace"></div>
</form>
</body>
I point out the button calls the ajax. There is no need to show you my ajax call because that works. It calls my createTable function when it gets the data back from the servlet. I know it is working because I can print the unique database id's with the console.log. However, the
document.getElementById("tablespace").innerHTML = tablecontents
is not working? Stranger is that when I run and view source on chrome. I see no error with the html. So I don't know what I am doing wrong?
tablecontents+="</table>" inplace of tablecontents="</table>"
Here's the problem:
tablecontents="</table>";
document.getElementById("tablespace").innerHTML = tablecontents;
You set "tablecontents" to be only the </table> tag. Should be:
tablecontents += "</table>"; // += not =
document.getElementById("tablespace").innerHTML = tablecontents;

Categories