I have got an unexpected behavior from my Javascript code. I'm creating a line of table with document.createElement("tr") and an array of cells with that code:
cellule = new Array(3).fill(document.createElement("td"));
But when I'm filling it with my values using innerHTML property case by case, the whole array is modified. Here is full code:
ligne = document.createElement("tr");;
cellule = new Array(3).fill(document.createElement("td"));
cellule[0].innerHTML = "Chat";
cellule[1].innerHTML = "Chien";
cellule[2].innerHTML = "Alligator";
ligne.appendChild(cellule[0]);
ligne.appendChild(cellule[1]);
ligne.appendChild(cellule[2]);
maTable.appendChild(ligne);
Results are :
cellule[0] => "Alligator"
cellule[1] => "Alligator"
cellule[2] => "Alligator"
Why is my whole array filled with the last innerHTML used?
Because 'filll' was used, the same td was copied, causing an issue. One way is to create an independent td.
ligne = document.createElement("tr");
var datas = ['Chat', 'Chien', 'Alligator'];
for(var i=0; i<datas.length; i++) {
var td = document.createElement("td");
td.innerHTML = datas[i];
ligne.appendChild(td);
}
maTable.appendChild(ligne);
Your issue is with:
cellule = new Array(3).fill(document.createElement("td"));
Here you are creating an array with 3 of the same td elements. So when you change the one at index 0, you are also changing the one at index 1 and 2 as you are referencing the same element in memory.
An easy way to fix this is to manually create an array using a for loop and pushing unique references of the element into your cellule array.
See example below:
var maTable = document.getElementById("myTable");
var ligne = document.createElement("tr");;
var cellule = [];
for(var i = 0; i < 3; i++) {
cellule.push(document.createElement("td"));
}
cellule[0].textContent = "Chat"; // use textContent instead of innerHTML if only adding text
cellule[1].textContent = "Chien";
cellule[2].textContent = "Alligator";
ligne.appendChild(cellule[0]);
ligne.appendChild(cellule[1]);
ligne.appendChild(cellule[2]);
maTable.appendChild(ligne);
<table id="myTable" border="1"></table>
fill add the same element (with the same reference) into your array.
You can put your elements with another way, like
cellule = [];
for (let i = 3; i--;) {
cellule.push(document.createElement("td"));
}
or
cellule = new Array(3);
for (let i = cellule.length; i--;) {
cellule[i] = document.createElement("td");
}
When fill gets passed an object, it will copy the reference and fill
the array with references to that object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#Description
Here is one of the way you could achieve the same.
cellule = new Array(3).fill("")
cellule.forEach((el,index) => cellule[index] = document.createElement("td"))
cellule[0].textContent = "Chat";
cellule[1].textContent = "Chien";
cellule[2].textContent = "Alligator";
console.log(cellule[0].textContent);
console.log(cellule[1].textContent);
console.log(cellule[2].textContent);
Related
I have a script that creates a table with specifications given by the user.
The issue is that when the table is printed more than once, it prints below the other table. Turning a 10x10 table into a 10x20 table. (if that makes sense)
In previous assignments I used:
//Clean grid
while(grid.firstChild)
grid.removeChild(grid.firstChild);
to clear the grid, but this assignment is using jQuery and I am not sure how to do it. I've tried:
var divBlock = document.getElementById('my_table');
while (divBlock.firstChild) {
divBlock.removeChild(divBlock.firstChild);
and
$("#my_table").empty();
and
$("#my_table").remove();
and
$('#my_table').remove('table');
but neither seem to work, here is the full code:
// TODO: clear table
var $rows = $("#rows");
var $cols = $("#cols");
var $print_button = $("#print");
var $my_table = $("#my_table");
var $stats = $("#stats");
var arr = [];
var $table_obj = $('<table>'); //Create an element
var $row_obj;
var $col_obj;
var counter = 0;
$print_button.on('click', function() {print_pattern();});
function print_pattern()
{
// Clear table
// var divBlock = document.getElementById('my_table');
// while (divBlock.firstChild) {
// divBlock.removeChild(divBlock.firstChild);
// }
// $("#my_table").empty();
$('#my_table').remove('table');
// Get row and column values
var r = $rows.val(); //Get value of rows
element
var c = $cols.val(); //Get value of cols element
// Create 2-D Array
for (var i = 0; i < r; i++) {
arr[i] = [];
}
// Double for-loop to create table
for (var i = 0; i < r; i++) {
$row_obj = $('<tr>'); // Create row
for (var j = 0; j < c; j++) {
$col_obj = $('<td>'); // Create table cell
var n = Math.floor(Math.random()*10000)%100; //Math methods:
floor and random
$($col_obj).append(n); // Append random number to table cell
$($row_obj).append($col_obj); // Append column to row
$($table_obj).append($row_obj); // Append row to table object
// if random number > 90 -> make background color yellow
if (n > 90) {
$col_obj.css('background-color', 'yellow'); //Change css
counter++; // counter for stats
}
}
$($table_obj).append($row_obj); // Append row to table object
}
$($my_table).append($table_obj); // Append table to div container
// Stats calculation
$stats.html("<b>" + (counter/(r*c)*100).toFixed(2) + "%<b>");
//Change html content
counter = 0; // reset counter
// event function for removing a row when its clicked on
$('tr').on('click', function(){ $(this).fadeOut(500); });
}
So I've tried a number of things, I am not sure if I am just getting the syntax wrong or if I am using the wrong function to clear the div tag.
If anyone can point me in the right direction that would help a lot!
Thank you.
EDIT: I figured out the issue. My original while() block worked fine when I put all the variables inside the function.
First of all, you have to distinguish variables.
A. There is a variable that has to define 1 time, and any changes will
be stored on that.
B. And there is a variable that needs to be reset every function
called.
variable on condition b you need put inside your function so it won't keep last value and make it has double value (last value + new value)
in this case i could say this variable is on condition b:
$table_obj, $row_obj, $col_obj, arr, ...
I am trying to add this code in for-loop but it is giving me below error
"Failed to execute 'appendChild' on 'Node': parameter 1 is not of type
'Node'"
let tableBody = document.querySelector('#table tbody');
let row1 = document.createElement('tr');
let row2 = row1.cloneNode(true);
let row3 = row1.cloneNode(true);
let row4 = row1.cloneNode(true);
let row5 = row1.cloneNode(true);
tableBody.appendChild(row1);
tableBody.appendChild(row2);
tableBody.appendChild(row3);
tableBody.appendChild(row4);
tableBody.appendChild(row5);
I am trying like this
for(i = 1; i <=5; i++){
tableBody.appendChild('row' + i);
}
You are not appending the actual object. You are appending a string.
Try it like that:
let tableBody = document.querySelector('#table tbody');
let rows = []
rows.push(document.createElement('tr'));
rows.push(rows[0].cloneNode(true));
rows.push(rows[0].cloneNode(true));
rows.push(rows[0].cloneNode(true));
rows.push(rows[0].cloneNode(true));
rows.forEach(row => {
tableBody.appendChild(row);
})
The reason you code tableBody.appendChild('row' + i); is not working 'row' + i is nothing but a sting , which is not a variable holding a node,
put all the rows in array and add it from there
try this
let tableBody = document.querySelector('#table tbody');
let rows=[];
rows.push(document.createElement('tr'));
rows.push(row1.cloneNode(true));
rows.push(row1.cloneNode(true));
rows.push(row1.cloneNode(true));
rows.push(row1.cloneNode(true));
for(i = 0 ; i <rows.length; i++){
tableBody.appendChild(row[i]);
}
Suggesting reading : Array, variables, function
appendChild takes DOM node object (https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild), As mentioned by others you are providing a string.
It looks as though you want to create a table with 5 rows, if so, this is how you could go about it:
for(i = 1; i <=5; i++){
tableBody.appendChild(document.createElement('tr'));
}
I want to make json object of html table in javascript.Currently I am able to read the each cells value in javascript, the only problem is that I am not able to retrieve as per my need so think of any suggestion here. Currently getting value like:
var x = document.getElementById("tableId");
for (var i = 0; i < x.rows.length; i++) {
for (var j = 0; j < x.rows[i].cells.length; j++){
tableJsonDTO[name] = x.rows[i].cells[j].innerHTML;
}
}
This is how i am able to read the each cell value.The table format is as follow:
header: company_1 company_2 company_3
Question1 answer_1 answer_1 answer_1
Question2 answer_2 answer_2 answer_2
and so on.How can i read the value so that i can get object like:
var obj = [{spname:"company_1",qalist:[{question:"",answer:""},{question:"",answer:""}]},{spname:"company_2",qalist:[{question:"",answer:""},{question:"",answer:""}]},{spname:"company_3",qalist:[{question:"",answer:""},{question:"",answer:""}]}]
Please give some suggestion.
You simply need to change the way you put values to tableJsonDTO. Demo.
document.getElementById('toJSON').addEventListener('click', function(){
var table = document.getElementById('mytable'),
names = [].slice.call(table.rows[0].cells),
values = [].slice.call(table.rows, 1),
out = {};
values.forEach(function(row) { //iterate over values
var cells = row.cells,
caption = cells[0].innerHTML; //get property name
[].forEach.call(cells, function(cell, idx) { //iterate over answers
var value = {},
arr;
if(!idx) return; //ignore first column
value[caption] = cell.innerHTML; //prepare value
//get or init array of values for each name
arr = out[names[idx].innerHTML] || (out[names[idx].innerHTML] = []);
arr.push(value);
});
});
console.log(out);
});
i am a javascript newbie. I have a 9*9 grid for my sudoku game. The html is such that each box of the grid is an inputelement with id like r1c4 where 1 is the row number and 4 is column number. I have half filled grid.I needed to store all the numbers in the grid in a two dimensional array.I have created the following function fo:
function getValues(){
var grid = new Array();
var colData = new Array();
var targetId;
for(var i=1;i<=9;i++)
{
for(var j=1;j<=9;j++)
{
targetId = 'r' + i + 'c' + j;
colData[j-1] = document.querySelector('#'+targetId).value;
}
grid[i-1] = colData;
console.log(grid[i-1]); // here logged correctly
}
return grid; // here returned wrong
}
The problem i am facing is that the returned array consists of only the last element repeated 9 times. I am logging the stored value every time by using console.log(grid[i-1]); and it is giving correct results.I am not getting it.
Regards.
grid[i-1] = colData;
You are not copying colData to grid[i-1], but simply making grid[i-1] a reference to colData. So, all the elements in your array are just references to the same object, colData.
To fix this problem, you need to create a new Array on every iteration. So, I would have done it like this
function getValues() {
var grid = [], colData, targetId;
for (var i = 1; i <= 9; i++) {
colData = []; // new Array on every iteration
for (var j = 1; j <= 9; j++) {
targetId = 'r' + i + 'c' + j;
colData.push(document.querySelector('#' + targetId).value);
}
grid.push(colData);
}
return grid;
}
You need to create a new colData per iteration rather than using the same one each time.
for(var i=1;i<=9;i++)
{
var colData = new Array();
...
Try either moving colData = new Array() (or better, colData = [];) inside the i for loop.
OR use grid[i-1] = colData.slice(0);.
Either way, you need to create a new array for each row, not just re-use the old one.
You're using the same Array object for every single column, and just overwriting the values. You're pushing 9 references to that same array into your grid.
You need to move var colData = new Array(); inside the loop so you're making a new Array for each column.
I have been working on a scheduling website for the past few weeks. I am showing the schedules as PHP generated html-tables. I use merged cells for showing events. I have come to a problem when trying to delete events using JS. Since those are merged cells, using rowspan, I have to go through the table and re-adding empty cells whenever there is a need when I delete one. My solution is working fine for when my table contains one merged cell among nothing but empty cells, but with a more complex table, it fails. I can't really grasp what's wrong with it, except that it doesn't correctly find the cellIndex anymore. Does anyone have a clue? Here is what I'm talking about:
http://aturpin.mangerinc.com/table.html
(Click on an event to remove it, or attempt to anyhow)
This sample may help you find your solution. It seems to demonstrate your problem as well as have some sample code to generate a matrix to help you solve it.
EDIT: I liked the puzzle and decided to play with it for a bit, here is a "functioning" example of implementing that sample (although sometimes the table doesn't seem to redraw correctly. This should probably help you get further along the way.
function getTableState(t) {
var matrix = [];
var lookup = {};
var trs = t.getElementsByTagName('TR');
var c;
for (var i=0; trs[i]; i++) {
lookup[i] = [];
for (var j=0; c = trs[i].cells[j]; j++) {
var rowIndex = c.parentNode.rowIndex;
var rowSpan = c.rowSpan || 1;
var colSpan = c.colSpan || 1;
var firstAvailCol;
// initalized the matrix in this row if needed.
if(typeof(matrix[rowIndex])=="undefined") { matrix[rowIndex] = []; }
// Find first available column in the first row
for (var k=0; k<matrix[rowIndex].length+1; k++) {
if (typeof(matrix[rowIndex][k])=="undefined") {
firstAvailCol = k;
break;
}
}
lookup[rowIndex][c.cellIndex] = firstAvailCol;
for (var k=rowIndex; k<rowIndex+rowSpan; k++) {
if(typeof(matrix[k])=="undefined") { matrix[k] = []; }
var matrixrow = matrix[k];
for (var l=firstAvailCol; l<firstAvailCol+colSpan; l++) {
matrixrow[l] = {cell: c, rowIndex: rowIndex};
}
}
}
}
// lets build a little object that has some useful funcitons for this table state.
return {
cellMatrix: matrix,
lookupTable: lookup,
// returns the "Real" column number from a passed in cell
getRealColFromElement: function (cell)
{
var row = cell.parentNode.rowIndex;
var col = cell.cellIndex;
return this.lookupTable[row][col];
},
// returns the "point" to insert at for a square in the perceived row/column
getPointForRowAndColumn: function (row,col)
{
var matrixRow = this.cellMatrix[row];
var ret = 0;
// lets look at the matrix again - this time any row that shouldn't be in this row doesn't count.
for (var i=0; i<col; i++)
{
if (matrixRow[i].rowIndex == row) ret++;
}
return ret;
}
};
}
function scheduleClick(e)
{
if (e.target.className != 'event')
return;
//Get useful info before deletion
var numRows = e.target.rowSpan;
var cellIndex = e.target.cellIndex;
var rowIndex = e.target.parentNode.rowIndex;
var table = e.target.parentNode.parentNode;
var tableState = getTableState(table);
var colIndex = tableState.getRealColFromElement(e.target);
//Deletion
e.target.parentNode.deleteCell(cellIndex);
//Insert empty cells in each row
for(var i = 0; i < numRows; i++)
{
var row = table.rows[rowIndex + i];
row.insertCell(tableState.getPointForRowAndColumn(rowIndex+i, colIndex));
}
}