Create table rows with Javascript - javascript

I'm new to Javascript and learn about querySelector(), createElement(), setAttribute and loop.
I try to create a table with a row, which contains 5 cells in it.
Imagine I create in HTML file. I use following code to execute my idea:
// 1. select id = pixelCanvas and store in var table.
const table = document.querySelector('#pixelCanvas');
// 2. create table row element <tr></tr> and append to var table.
table.appendChild(document.createElement('tr'));
// 3. create element table data and store in var data.
const data = document.createElement('td');
// 4. set html attribute with class="cell", width: 20px & height: 20px for table data
data.setAttribute('style', 'width: 20px; height: 20px:');
// 5. use for loop and appendChild() to append 5 <td></td> to <tr></tr>
for (i = 0; i < 5; i++) {
let tblRow = document.querySelector('tr');
tblRow.appendChild(data);
};
Here is the result in HTML page.
Obviously my idea doesn't work as expected. Appreciate your advice: where goes wrong?

prefer to use css to style attributes.
there is also js methods for tables :
HTMLTableElement.insertRow()
HTMLTableRowElement.insertCell()
const myTable = document.querySelector('table#pixelCanvas')
for (let r=0;r<5;++r) {
let row = myTable.insertRow()
for (c=0;c<5;++c) {
row.insertCell().textContent = `${r}.${c}`
}
}
table#pixelCanvas {
border-collapse: collapse;
font-size: 9px;
}
table#pixelCanvas td {
padding: 5px;
width: 20px;
height: 20px;
border: 1px solid black;
}
<table id="pixelCanvas"></table>

Your code is very close to working - you just need to create a seperate td element for each iteration of the for loop, and setting the style attribute is much easier when done via the .style property of the element.
Also instead of trying to query for the row you have just created, you can use the return value of the createElement function - it will give you the variable containing the new element.
See this snippet:
const table = document.querySelector('#pixelCanvas');
const colors = ["red", "orange", "green", "blue", "purple"];
const row = document.createElement('tr');
table.appendChild(row);
for (i = 0; i < 5; i++) {
const cell = document.createElement('td');
cell.style.width = "20px";
cell.style.height = "20px";
cell.style.backgroundColor = colors[i];
row.appendChild(cell);
};
<table id="pixelCanvas"></table>

You mean this
Move the row outside the loop and if you need the cells to be the same, clone the one you made - you also had a typo in it (colon instead of semicolon)
I would also target the tbody since a table should have such a thing
const table = document.querySelector('#pixelCanvas tbody');
const data = document.createElement('td');
data.setAttribute('style', 'width: 20px; height: 20px;');
let tblRow = document.createElement('tr');
for (let i = 0; i < 5; i++) {
let cell = data.cloneNode(true)
cell.textContent = i;
tblRow.appendChild(cell);
}
table.appendChild(tblRow);
<table id="pixelCanvas">
<thead>
</thead>
<tbody>
</tbody>
</table>
Result
<table id="pixelCanvas">
<thead>
</thead>
<tbody>
<tr>
<td style="width: 20px; height: 20px;">0</td>
<td style="width: 20px; height: 20px;">1</td>
<td style="width: 20px; height: 20px;">2</td>
<td style="width: 20px; height: 20px;">3</td>
<td style="width: 20px; height: 20px;">4</td>
</tr>
</tbody>
</table>

Related

Unable to reference a dynamically created table using document.getElementById()

I am trying to reference the table from a function outside createHTMLTableFromTableObject() using document.getElementById(). I have created a button that prints to the console the reference to the position in the table but all I'm getting is an error. I am obviously not referencing the table correctly but everything ive found online says this is how its done. when i do the exact same console statement inside the createHTMLTableFromTableObject(), it is referenced perfectly. What am i doing wrong and is there any way to reference the table correctly?. Note that this is part of a wider bit of code that randomly generates info for the table, i have cut this out and replaced it with "-" in each cell.
<!DOCTYPE html>
<html>
<style>
p,
input {
font: 14px Verdana;
}
.code {
margin-left: auto;
margin-right: auto;
width: 50%;
}
tr:nth-child(even) {background: #FFF}
tr:nth-child(odd) {background: rgb(228, 228, 228)}
.htmlTable {
border: solid 2px #000;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
}
.thCell {
border: solid 1px #000;
border-collapse: collapse;
padding: 8px 8px;
background-color:rgb(136, 136, 136);
font: 14px Verdana;
color: black;
font-weight: bold;
}
.thAlign {
text-align: center;
}
.tdCell {
border: solid 1px #000;
border-collapse: collapse;
padding: 8px 8px;
font: 14px Verdana;
color: black;
}
.tdTxtAlign {
text-align: left;
}
.tdNumAlign {
text-align: right;
}
</style>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Convert JavaScript Object Data to HTML Table</title>
</head>
<body>
<!-- View showing Table containing randonly generated data -->
<!-- And a Button to generate another random table-->
<div>
<div style="padding: 20px; text-align: center;"><input type="button" onclick="createHTMLTableFromTableObject()"
value="Create Table From JavaScript Object" /></div>
<table style="padding: 20px;" id="showTableData"></table>
<div style="padding: 20px; text-align: center;"><input type="button" onclick="testRef()"
value="Test Reference to Table" /></div>
</div>
<!-- Function to generate a JS Table Object, and a function to convert to HTML Table -->
<script>
//
// The table object - it is the data model!
//
var myTable = [];
//
// generate random data to populate the table model (populates a JavaScript object)
//
function genNewTable(table, numRows) {
for (i = 0; i < numRows; i++) {
// generate table row with random data
table.push({
"Student Name": "-",
"Student ID": "-",
"Assignment 1": "-",
"Assignment 2": "-",
"Assignment 3": "-",
"Assignment 4": "-",
"Assignment 5": "-",
"Average (%)": null
});
// calculate the average grade for the last generated record inserted into table
numAssignments = -3; averageGrade = 0;
studentRecord = table[table.length - 1];
// get the keys for any column matching "assignment"
// var assignmentKeys = Object.keys(studentRecord).filter((assignment) => /Assignment/.test(assignment));
// get total grades (not averaged) just to see what you can do with filter
// Object.keys(studentRecord).filter((assignment) => averageGrade += (/Assignment/.test(assignment))?studentRecord[assignment]:0);
for (var column in studentRecord) {
if (/^Assignment/.test(column))
averageGrade += studentRecord[column];
numAssignments++;
}
averageGrade = Math.round(averageGrade / numAssignments);
// set the final column to the average grade for the randomly generated grades
studentRecord["Average (%)"] = averageGrade +"%";
}
}
//
// generate a table from the JavaScript (JSON) object
//
function createHTMLTableFromTableObject() {
// generate a new table using random data
myTable = []; genNewTable(myTable, 10);
// extract the column headers from the current data model (using first row of data model)
var colHeaders = Object.keys(myTable[0]);
// create the <table> object for inserting into DOM
var table = document.createElement("table");
table.setAttribute("class", "htmlTable");
// create the <table> header row first using extracted headers
var tr = table.insertRow(-1); // create the row (at end of table)
for (var i = 0; i < colHeaders.length; i++) {
var th = document.createElement("th"); // and the headers
th.setAttribute("class", "thCell thAlign"); // add the styles
th.innerHTML = colHeaders[i];
tr.appendChild(th);
}
// add the data from the table object as rows
for (var i = 0; i < myTable.length; i++) {
tr = table.insertRow(-1); // insert row at end of table
for (var j = 0; j < colHeaders.length; j++) {
var tabCell = tr.insertCell(-1); // insert at end of row
if (j<2) {
tabCell.setAttribute("class", "tdCell tdTxtAlign");
} else {
tabCell.setAttribute("class", "tdCell tdNumAlign");
tabCell.contentEditable = true;
}
tabCell.innerHTML = myTable[i][colHeaders[j]];
//console.log(table.rows[i+1].cells[j]); <---------- PERFECT REFERENCE
}
}
// now update the table view (container)
var viewContainer = document.getElementById("showTableData");
viewContainer.innerHTML = ""; // reset
viewContainer.appendChild(table); // add the table
}
function testRef()
{
var table = document.getElementById("showTableData");
console.log(table.rows[0].cells[1]);
}
</script>
</body>
</html>
This is because you are placing that generated table into the already existing table (with id: showTableData) and then you are calling that table.
it would return something like <table id="showTableData"><table class="htmlTable"></table></table>
and you want to address the second one or better yet don't place a table inside the other table :)
function testRef()
{
var table = document.querySelector(".htmlTable");
console.log(table.rows[0].cells[1]);
}
this is a quick fix (proof) but you should spawn that generated table into the container directly.
Edit 1: answering further question
in javascript change
table.setAttribute("class", "htmlTable");
to
table.setAttribute("id", "showTableData");
you can also keep both if you need that class name.
Next this line that currently addresses the first table
var viewContainer = document.getElementById("showTableData");
change to
var viewContainer = document.getElementById("showTableData_container");
and lastly in HTML
<table style="padding: 20px;" id="showTableData"></table>
to this
<div style="padding: 20px;" id="showTableData_container"></div>
you can now use the original test function
function testRef()
{
var table = document.getElementById("showTableData");
console.log(table.rows[0].cells[1]);
}
In your code yo wrote:
// create the <table> object for inserting into DOM
var table = document.createElement("table");
table.setAttribute("class", "htmlTable");
And this table is not the same to the one with id="showTableData"
To get the content of the first row of the table that you create with the function createHTMLTableFromTableObject:
function testRef(){
var table = document.querySelector(".htmlTable");
console.log(table.rows[0].cells[1]);
}

Returning Row Index from JavaScript function ,returns undefined

function getRowIndex() {
var tble = document.getElementById("myTable");
for (var i = 0; i < tble.rows.length; i++) {
for (var j = 0; j < tble.rows[i].cells.length; j++) {
tble.rows[i].cells[j].onclick = function() {
return this.parentElement.rowIndex;
}
}
}
}
var rIndex = getRowIndex();
console.log(rIndex);
This function getRowIndex() is returning undefined when I try to print index. I want to extract the row index value in value when clicked, using javaScript.
I am assuming that you are using HTML table element. You can find row index like this:
document.getElementById('myTable').addEventListener('click', (e) => {
if (e.target.nodeName === 'TD') {
alert(e.target.parentNode.rowIndex);
}
});
table {
border-collapse: collapse;
}
td {
border: 1px solid;
padding: 10px;
cursor: pointer;
}
<table id="myTable">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
</table>
I am using event delegation here. Instead of iterating over each child element and then bind the event. I am binding the event to parent node itself and then find the click target using event.target. This has great performance benefits as you can already see.

Why do my HTML table columns resize when I dynamically add a row containing a div?

I am trying to add a table row containing a div dynamically using JavaScript. Everything is working fine except, when it is added, my columns move slightly. Weirdly, it seems to only happen when the div contains text longer than a certain length.
In the stripped down version below, you can see the problem clearly. After trying it, go to line 24 of the JavaScript, remove the "i" at the end of the string, and it will no longer move my columns.
JSFiddle
setEventListeners();
function setEventListeners() {
var hideMe = document.getElementById('hide-me');
var table = document.getElementById('table');
hideMe.addEventListener('mouseenter', showHoverMenu);
table.addEventListener('mouseleave', deleteOtherMenus);
}
function showHoverMenu(e) {
e.preventDefault();
deleteOtherMenus();
var tr = document.createElement('tr');
tr.setAttribute('class', 'row-menu-parent')
var td = document.createElement('td');
td.colSpan = 4;
var rowMenu = document.createElement('div');
rowMenu.classList.add('row-menu');
var div = document.createElement('div');
// Delete the "i" at the end of the string and try hovering again
div.innerHTML = 'abcdefghi';
rowMenu.appendChild(div);
td.appendChild(rowMenu);
tr.appendChild(td);
var target = e.currentTarget;
target.parentNode.insertBefore(tr, target.nextSibling);
}
function deleteOtherMenus() {
var rowMenu = document.getElementsByClassName('row-menu-parent');
if (rowMenu.length > 0) {
rowMenu[0].parentNode.removeChild(rowMenu[0]);
}
}
* {
border: 1px solid red;
}
table {
width: 100%;
}
.row-menu div {
background-color: lightGrey;
}
<table id="table">
<tr id="hide-me">
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
</tr>
</table>
What is causing my columns to move, and how do I fix it?
EDIT: The columns need to be able to automatically resize, so a fixed table layout will not work.
You can set your table to table-layout: fixed; if you don't want it resizing.
table {
table-layout: fixed; /* Add this */
width: 100%;
}
setEventListeners();
function setEventListeners() {
var hideMe = document.getElementById('hide-me');
var table = document.getElementById('table');
hideMe.addEventListener('mouseenter', showHoverMenu);
table.addEventListener('mouseleave', deleteOtherMenus);
}
function showHoverMenu(e) {
e.preventDefault();
deleteOtherMenus();
var tr = document.createElement('tr');
tr.setAttribute('class', 'row-menu-parent')
var td = document.createElement('td');
td.colSpan = 4;
var rowMenu = document.createElement('div');
rowMenu.classList.add('row-menu');
var div = document.createElement('div');
// Delete the "i" at the end of the string and try hovering again
div.innerHTML = 'abcdefghi';
rowMenu.appendChild(div);
td.appendChild(rowMenu);
tr.appendChild(td);
var target = e.currentTarget;
target.parentNode.insertBefore(tr, target.nextSibling);
}
function deleteOtherMenus() {
var rowMenu = document.getElementsByClassName('row-menu-parent');
if (rowMenu.length > 0) {
rowMenu[0].parentNode.removeChild(rowMenu[0]);
}
}
* {
border: 1px solid red;
}
table {
table-layout: fixed;
width: 100%;
}
.row-menu div {
background-color: lightGrey;
}
<table id="table">
<tr id="hide-me">
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
</tr>
</table>
Try setting box-sizing: border-box in CSS for the table and/or wrap the .row-menu div in a div that does not have any styling.
If you look closely, the inner div's border is expanding the size of the parent TD which is causing the table to re-adjust.

Change background color onClick of column in a dynamically populated table

I am dynamically creating HTML table like this :
for(var i=0; i<rowsToAdd ; i++){
tr = table.insertRow(-1);
var colsToAddLength = findColsToAddLength();
for(var j=0; j<colsToAddLength; j++){
var tabCell = tr.insertCell(-1);
var colToAdd = findColToAdd();
tabCell.innerHTML = colToAdd;
}
}
How can I change the color of a particular cell once it's clicked? I am a beginner in web development.
You can use it like this:
function alternate(id){
if(document.getElementsByTagName){
var table = document.getElementById(id);
var rows = table.getElementsByTagName("tr");
for(i = 0; i < rows.length; i++){
//manipulate rows
if(i % 2 == 0){
rows[i].className = "even";
}else{
rows[i].className = "odd";
}
}
}
}
<style>
.odd{background-color: white;}
.even{background-color: gray;}
</style>
<table id="theTable">
<tr><td>0 - some txt</td></tr>
<tr><td>1 - some txt</td></tr>
<tr><td>2 - some txt</td></tr>
<tr><td>3 - some txt</td></tr>
<tr><td>4 - some txt</td></tr>
</table>
As I like to avoid JS whenever it's not too much trouble doing same thing with CSS, I would suggest below trick, however I can't fully reproduce your case as you provided too few details. Colors can be controlled via additional CSS classes.
table {
border-collapse: collapse;
}
td {
position: relative;
border: 1px solid #000000;
padding: 0;
}
.pseudo-checkbox {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
opacity: 0;
}
.cell-content {
padding: 10px;
}
.pseudo-checkbox:checked + .cell-content {
background: red;
}
<table>
<tbody>
<tr>
<td>
<input type="checkbox" class="pseudo-checkbox" />
<div class="cell-content">
123
</div>
</td>
<td>
<input type="checkbox" class="pseudo-checkbox" />
<div class="cell-content">
123
</div>
</td>
<td>
<input type="checkbox" class="pseudo-checkbox" />
<div class="cell-content">
123
</div>
</td>
</tr>
</tbody>
</table>

JavaScript setAttribute ID to row is Undefined

I am attempting to give each row that is dynamically added a unique ID. Basically by adding to the number each time the user clicks the add button. It is adding an ID, but not correctly, it is showing up as "undefined" in the dev tools.
var counter = 0;
function appendRow(id, style) {
var table = document.getElementById(id); // table reference
length = table.length,
row = table.insertRow(table.rows.length, 'id'); // append table row
row.setAttribute('id', style);
row.setAttribute('idName', style);
var i;
// insert table cells to the new row
for (i = 0; i < table.rows[0].cells.length; i++) {
createCell(row.insertCell(i), i, 'cust' + counter);
counter++
}
}
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode('_'); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('id', style); // set DIV class attribute
div.setAttribute('idName', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
table {
text-align: center;
}
td {
width: 100px;
}
tr:nth-child(even) {
background-color: #fff;
}
tr:nth-child(odd) {
background-color: #eee;
}
<button id="addCust" class="addSort" onclick="appendRow('custList')">add customer</button>
<div class="custScroll">
<table id="custListTop" contenteditable="false">
<tr>
<td style="border-top-left-radius: 5px;">Customers</td>
<td style="border-top-right-radius: 5px;">Main Location</td>
</tr>
</table>
<table id="custList" contenteditable="true">
<tr>
<td>Someone</td>
<td>Somewhere</td>
</tr>
</table>
</div>
The reason why the new elements are showing up as "undefined" is because the style argument of appendRow has not been provided.
To get the functionality that you're going for you have to remove style from the appendRow arguments and replace the references to style inside appendRow with 'cust' + counter.
Your style value is null here please check style value I have also added fiddle
Please check this code, When user is clicking on button the style value is undefined.
<button id="addCust" class="addSort" ***onclick="appendRow('custList')"***>add customer</button>
Appendrow function requires two parameters and you are just passing one.
var counter = 0;
$('#addCust').click(function() {
var table = document.getElementById('custListTop'); // table reference
length = table.length,
row = table.insertRow(table.rows.length, 'id'); // append table row
row.setAttribute('id', counter);
row.setAttribute('idName', counter);
var i;
// insert table cells to the new row
for (i = 0; i < table.rows[0].cells.length; i++) {
createCell(row.insertCell(i), i, 'cust' + counter);
counter++
}
});
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode('_'); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('id', style); // set DIV class attribute
div.setAttribute('idName', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
table {
text-align: center;
}
td {
width: 100px;
}
tr:nth-child(even) {
background-color: #fff;
}
tr:nth-child(odd) {
background-color: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="addCust" class="addSort">add customer</button>
<div class="custScroll">
<table id="custListTop" contenteditable="false">
<tr>
<td style="border-top-left-radius: 5px;">Customers</td>
<td style="border-top-right-radius: 5px;">Main Location</td>
</tr>
</table>
<table id="custList" contenteditable="true">
<tr>
<td>Someone</td>
<td>Somewhere</td>
</tr>
</table>
</div>

Categories

Resources