Javascript Array or indices undefined - javascript

I am building a web app which contains a DOM table. This is my code that should create a table from an array:
function create_table() {
var tablediv=document.getElementById('icon-table');
var table = document.createElement("table");
var grid = [[15][15]];
var template = "pixel-{1}-{2}";
table.className = "icon-table";
tablediv.appendChild(table);
for (var i = 0; i < 16; i++) {
var tr = document.createElement("tr");
table.appendChild(tr);
for (var j = 0; j < 16; j++) {
var td = document.createElement("td");
td.className = "icon-pixel";
td.id="pixel-"+ i + "-" + j;
td.style.backgroundColor = "rgb(255,255,255)"; // no dash - css attribute name becomes camelCase
grid[i][j] = td;
td.addEventListener("click", setpixel)
td.addEventListener("mousedown", pinselpixel)
tr.appendChild(td);
}
}
}
The assignment grid[i][j] = td; fails during the first loop iteration.
On the console in my browser the output says:
TypeError: undefined is not an object (evaluating 'grid[i][j] = td')
what am I missing?

There's a couple of problems here. First, you seem to be under the impression that
[[15],[15]]
will create an an array with two sub-arrays, each with 15 keys.
Instead, what that actually gives you is an array with two sub-arrays each containing one key each, with the value 15.
You probably meant this:
[new Array(15), new Array(15)]
Passing an integer to the array constructor creates the slots; passing it to an array literal simply adds that value to the array.
Even then, this approach isn't ideal. Yes, you're containing 15 (actually you presumably meant 16) slots, but they're just undefined slots right now, so this line will fail, since you can't treat undefined as an array:
grid[i][j] = td; //grid[i] == undefined, not an array
Better this (truncated for brevity):
for (var i = 0; i < 16; i++) {
grid[i] = []; //<-- create the row array in the loop
var tr = document.createElement("tr");
table.appendChild(tr);
for (var j = 0; j < 16; j++) {
var td = document.createElement("td");
grid[i][j] = td; //<-- now we can append the column cell
tr.appendChild(td);
}
}

you are trying to loop over an array of array which has 2 elements inside. Each element is (like i said) an array, with a single entry - in your case 15.
Afterwards you are trying to iterate from 0 up to 15.
So your iterations should at first loop over grid array and afterwards over grid's elements up to their length.
but in my opinion it is not necessary to loop over an array here. just do the following:
var myGrid = []
for (var i = 0; i < 16; i++) {
for var k = 0; k < 16; k++) {
//do your stuff
myGrid[i][k] = td
}
}
this should work

The method of intializing the two dimensional array is wrong.
Please use the below method to initialize.
var grid = new Array(15);
for (var i = 0; i < 16; i++) {
grid[i] = new Array(15);
}
First we create the rows of the array (15 rows), then using a for loop we initialize 15 columns for each row. Then the code works fine!
function create_table() {
var tablediv=document.getElementById('icon-table');
var table = document.createElement("table");
var grid = new Array(15);
for (var i = 0; i < 16; i++) {
grid[i] = new Array(15);
}
var template = "pixel-{1}-{2}";
table.className = "icon-table";
tablediv.appendChild(table);
for (var i = 0; i < 16; i++) {
var tr = document.createElement("tr");
table.appendChild(tr);
for (var j = 0; j < 16; j++) {
var td = document.createElement("td");
td.className = "icon-pixel";
td.id="pixel-"+ i + "-" + j;
td.style.backgroundColor = "rgb(255,255,255)"; // no dash - css attribute name becomes camelCase
grid[i][j] = td;
td.addEventListener("click", function(){console.log("clicked");})
td.addEventListener("mousedown", function(){console.log("mousedown");})
tr.appendChild(td);
}
}
}
create_table();
<div id="icon-table"></div>

Your grid initialization is wrong. As mentioned by some comments:
var grid = [[15][15]];
is equivalent to:
const arr = [15]; // array with one element, 15
var grid = arr[15]; // 16th element, which doesn't exist
You probably instead want:
var grid = new Array(15).fill(new Array(15));
Which will give you a two-dimensional array that is 15 "wide" and 15 "tall".
That said, you really don't need to prefill your grid unless it is a requirement for some other reason (like you are printing out a chessboard or something that always has a fixed size).

Can change to this and try it?
var grid = [[15][15]];
to
var grid = [new Array(15), new Array(15)];

Related

Using Javascript create table (tableee added)

I'm putting tableee's(a list contains 36 elements) elements into my table(which is x) ,but It's would be a 6*6 matrix not just 1*1 matrix.
wrong
I need(just a likely example)
var x = document.createElement('table');
var y = document.createElement("tr");
var z = document.createElement("td");
document.body.appendChild(x);
for (var i=0; i<tableee.length; i++){
x.appendChild(y);
y.appendChild(z);
var t = document.createTextNode("why");
z.appendChild(t);
}
//console.log(tableee);
document.getElementById("table1").innerHTML = x;
I don't know what tableee is, but since you only use the length I've changed it to two variables rows and columns.
This should create the table structure you are looking for:
var columns = 6;
var rows = 6;
var table = document.createElement('table');
var tbody = document.createElement('tbody');
for (var i = 0; i < rows; i++){
var row = document.createElement('tr');
for (var j = 0; j < columns; j++){
var column = document.createElement('td');
var text = document.createTextNode('text');
column.appendChild(text);
row.appendChild(column);
}
tbody.appendChild(row);
}
table.appendChild(tbody);
document.body.appendChild(table);
table td {
border: 1px solid black;
padding: 2px 4px;
}
Also, it's a better idea to append the table to the document body at the end to avoid reflow/repaint calls on every iteration.
Thank you for providing the content of the variable tableee. So in my opinion I think you can use template strings (ES6 feature) to print all the content of the array but you will tweak the array to subdivide it into sub arrays
I made it programmatically but if you have direct access to the array, feel free to edit first to have the same form as in the code comments:
function splitarray(input) {
var output = [];
for (var i = 0; i < input.length; i += 6) {
output[output.length] = input.slice(i, i + 6);
}
return output;
}
// this is a dummie array I made up according to your tablee data in the screenshots
var tableee = ['1year', '2year', '3year', '4year', '5year', 'rate1%', '1.0100', '1.0201', '1.0303', '1.0406', '1.0510', 'rate2%', '1.0100', '1.0201', '1.0303', '1.0406', '1.0510', 'rate3%', '1.0100', '1.0201', '1.0303', '1.0406', '1.0510', 'rate4%', '1.0100', '1.0201', '1.0303', '1.0406', '1.0510', 'rate5%', '1.0100', '1.0201', '1.0303', '1.0406', '1.0510'];
// This is to add an empty string at the beginning of the array
tableee.unshift('');
// This is to slice the array into sub-array that have lenght of 6 each (to fit the required table)
// The array will have the form of [ [...](6), [...](6), [...](6), [...](6), [...](6), [...](6) ](6)
var newTableee = splitarray(tableee);
var x = '<table border="1"> <tbody>';
for (var i = 0; i < newTableee.length; i++) {
x += '<tr>';
for (var j = 0; j < 6; j++) {
x += `<td> ${newTableee[i][j]} </td>`; // Here is the use of template strings
}
x += '</tr>';
}
x += '</tbody> </table>';
document.getElementById('table1').innerHTML = x;
<div id="table1"></div>
hopefully this is a more specific answer to your issue.

Adapting merge cells in InDesign script

I found this script on SO, which is very close to what I need. But instead of it merging the cells with the one above I need it to merge with the cell to left of any empty cell.
I have tried to experiment with it and manged to get it to merge horizontally once but it merge three cells that weren't empty into one.
Would be greatful for any help
THanks
var myDoc = app.activeDocument;
myPage = myDoc.pages;
for (var p=0; myPage.length>p; p++){
try{
var myTable = myPage[p].textFrames.everyItem().tables.everyItem();
if (myTable.constructor.name == 'Table'){
for (var t = myTable.cells.length - 1; t >= 0; t--)
{
if (myTable.cells[t].contents==""){
var w = myTable.columns.length;
myTable.cells[t-w].merge(myTable.cells[t]);
}
}
}
}
catch(e){}
}
I found a solution
var i, j, cells;
// Get all the rows in the document
var rows = app.documents[0].stories.everyItem().tables.everyItem().rows.everyItem().getElements();
for (i = 0; i < rows.length; i++) {
// Get all the cells in a row
cells = rows[i].cells.everyItem().getElements();
for (j = cells.length-1; j >= 1; j--) {
if (cells[j].contents == '') {
cells[j-1].merge (cells[j]);
}
}
}

Unable to append row through javascript function

Im trying to append a row to a table. And this is the code that i tried
function load() {
for (var k = 0; k < 1; k++) {
var myTableDiv = document.getElementById("pID");
var tableBody = document.getElementById("tBody");
var table = document.getElementById('pTable');
table.appendChild(tableBody);
for (var i = 0; i < 3; i++) {
var tr = document.getElementById('RiskRow');
tableBody.appendChild(tr);
for (var j = 0; j < 1; j++) {
var element1= document.getElementById('RiskTD');
var element2= document.getElementById('severityTD');
var element3= document.getElementById('mitigationTD');
var element4= document.getElementById('contingencyTD');
var element5= document.getElementById('riskStatusTD');
tr.appendChild(element1);
tr.appendChild(element2);
tr.appendChild(element3);
tr.appendChild(element4);
tr.appendChild(element5);
}
}
myTableDiv.appendChild(table);
}
}
But this results in appending only one row. I need multiple rows to be added that follows the for loop. Im not sure where i stuck up.
Regardless of the redundant loops you have there (var k = 0; k < 1 will always perform once...), the reason you're seeing this behavior is because you're trying to append the same element over and over. This will cause the element to be moved, rather than copied.
Have a look at document.cloneNode

Problems using x.length within for loop

I'm having problems trying to dynamically generate an HTML table based on input (column/row) values.
When I hardcode the values in the loop below (i.e. instead of using the prompt), it creates the correct number of cells. However, when using x.length within the loop, something isn't working correctly.
works correctly:
function createTable() {
// declare variables
var body = document.body,
table = document.createElement('table');
// Begin creating table
// for each row
for(var r = 0; r < 8; r++) {
// create row
var tr = table.insertRow();
// for each column
for(var c = 0; c < 8; c++) {
// create column
var td = tr.insertCell();
td.appendChild(document.createTextNode('Cell'));
}
}
// append table to body
body.appendChild(table);
}
createTable();
does not create correct cells based on variable input
function createTable() {
// declare variables
var body = document.body,
table = document.createElement('table'),
rows = prompt("enter rows"),
columns = prompt("enter columns");
// Begin creating table
// for each row
for(var r = 0; r < rows.length; r++) {
// create row
var tr = table.insertRow();
// for each column
for(var c = 0; c < columns.length; c++) {
// create column
var td = tr.insertCell();
td.appendChild(document.createTextNode('Cell'));
}
}
// append table to body
body.appendChild(table);
}
createTable();
rows and columns are strings, that's the only reason why they have a .length. You seem to want to use them as parsed numbers, without any lengths:
var body = document.body,
table = document.createElement('table'),
rows = parseInt(prompt("enter rows"), 10),
columns = parseInt(prompt("enter columns"), 10);
for (var r = 0; r < rows; r++) {
var tr = table.insertRow();
for (var c = 0; c < columns; c++) {
var td = tr.insertCell();
td.appendChild(document.createTextNode('Cell'));
}
}
body.appendChild(table);
Use parseInt(rows) and parseInt(columns). This functions return an integer but you must check if the input is really an string-represented integer value.

Create an Array with Data from TD Tags

I want to export an HTML table into a spreadsheet that will be created by the JavaScript program. I've considered doing this via the JQuery library but I don't know much about it nor do I think that it will be allowed in my situation. I have seen a solution that uses XML but I don't know much about XML either. What I intend on doing is creating a 2 dimensional array and exporting the contents of that array into Excel. Unfortunately, I don't have control over the tagging scheme and I will have to use getElementsByTagName. The tagging scheme is created via a reporting software.
The below code loops to the second row but it stops at the second row. I can't figure out what I am doing wrong. I hope that somebody will be able to explain a remedy to the error.
<!DOCTYPE html>
<html>
<body>
<table>
<tr><td>a</td><td>1</td></tr>
<tr><td>b</td><td>2</td></tr>
<tr><td>c</td><td>3</td></tr>
<tr><td>d</td><td>4</td></tr>
</table>
<script>
var myNodelist = document.getElementsByTagName("td");
var NumTD= (document.getElementsByTagName("td").length);
var NumTR= (document.getElementsByTagName("tr").length);
var NumCol=NumTD/NumTR;
var array1 = [[]];
var c=0;
var r=0;
alert("NumTD is: "+NumTD);
for (var i=0;i<=NumTD;i++) {
alert("On TD: "+i);
alert(myNodelist[i].innerHTML);
alert("r: "+r);
alert("c: "+c);
array1[r][c]=myNodelist[i].innerHTML;
alert("The array is at: "+array1[r][c]);
if((c+1)==NumCol) {
c=0;
} else {
c++;
}
if(c==0) {
r++;
}
}
</script>
</body>
</html>
Issue 1: Work on your formatting. It's a lot easier to debug your own code when you indent correctly, use new lines effectively, and use descriptive variable names.
Issue 2: Uncaught TypeError: Cannot set property '0' of undefined on line 19. You're trying to set array1[0][0] when array1[0] isn't an array. You need to make array[0] an array before you try to use it as one, like this:
if(!array1[i]){
array1[i] = [];
}
This checks if your array exists. If it doesn't, then it is set to an empty array.
Issue 3: Uncaught TypeError: Cannot read property 'innerHTML' of undefined on line 24. Your loop runs from 0 to 8 and myNodeList only goes up to 7. Changing for (var i=0;i<=NumTD;i++) to for (var i=0;i<NumTD;i++) solves this issue by restricting the bounds of the loop.
Issue 4: Messing around with 3 indices (r, c, and i) is unnecessary and doesn't make things any easier. For one, c and i are always equal, so we can run the loop from c = 0 to c < numTD.
Issue 5: Checking if c + 1 is equal to the number of columns is clumsy. Instead, your second dimension should be c % numCol, which is just the remainder of c divided by numCol. It works perfectly here. We can also increment r when c % numCol is 0.
var myNodelist = document.getElementsByTagName("td");
var numTD = myNodelist.length;
var numTR = document.getElementsByTagName("tr").length;
var numCol = numTD/numTR;
var array1 = [];
var r = 0;
for(var c = 0; c < numTD; c++){
array1[r] = array1[r] || [];
array1[r][c % numCol] = myNodelist[c].innerHTML;
if(c % numCol){
r++;
}
}
Working example
Issue 6: This approach is generally a clumsy way to accomplish the task. It'd be a lot cleaner to grab each row, iterate through them, and grab the individual cells then. Edit: Got this is right before I saw #dc5's edit. His works just as well.
var rows = document.getElementsByTagName("tr");
var results = [];
for(var i = 0; i < rows.length; i++){
var cells = rows[i].getElementsByTagName("td");
results[i] = [];
for(var j = 0; j < cells.length; j++){
results[i][j] = cells[j].innerHTML;
}
}
Working example
With your current logic, you have a couple of problems:
array1 is initialized as [[]]
r (the row counter) is never incremented
Your for loop: for (var i=0;i<=NumTD;i++) should be for (var i=0;i<NumTD;i++)
The values read from the table are always updating the value at array1[0,0] and array1[0,1]
The fix - for the current logic, is to increment r when ever the column counter is reset to zero and to insert a new empty array at the new row if it doesn't already exist.
Code:
var myNodelist = document.getElementsByTagName("td");
var NumTD = (document.getElementsByTagName("td").length);
var NumTR = (document.getElementsByTagName("tr").length);
var NumCol = NumTD / NumTR;
var array1 = []; // <== initialize as empty array
var c = 0;
var r = 0;
for (var i = 0; i < NumTD; i++) {
array1[r] = array1[r] || []; // <== If array at row doesn't exist,
// initialize it to a new array
array1[r][c] = myNodelist[i].innerHTML;
if ((c + 1) == NumCol) {
c = 0;
r++; // <== increment the row
} else {
c++;
}
}
jsFiddle demo
The above code could be simplified a bit by querying the table rows first, then iterating the rows, querying the child td's for each found row.
For example:
var rows = document.getElementsByTagName("tr");
var rowCount = rows.length;
var r, c, cols, colCount;
var array1 = [];
for (r = 0; r < rowCount; ++r) {
array1[r] = [];
cols = rows[r].getElementsByTagName("td");
colCount = cols.length;
for(c = 0; c < colCount; ++c) {
array1[r][c] = cols[c].innerHTML;
}
}
jsFiddle demo

Categories