Trouble with Javascript table colspan - javascript

I'm trying to make some of my columns span for readability, as well as pattern recognition. I'm also changing the background color of the cells to show patterns. If the data in my array is null, I use red. If it is not null and spans at least 2 columns, it is blue, otherwise, it is grey. I'm finding that some of my columns are wider than they should be, and some are shorter. With my data, the first columns are the only ones too wide, and the last are the only ones too short. So far as I can tell however, their colors are correct. I can give example code, but not example data as it is highly confidential. I can give the code, and will. Why are some of my columns wider, and others shorter than I expect them to be?
function loadTable() {
var fields = JSON.parse(localStorage.getItem("boxFields"));
var report = JSON.parse(localStorage.getItem("boxReport"));
var space = document.getElementById("batchReport");
var baseList = document.createElement("ul");
space.appendChild(baseList);
for (var i = 0; i < fields.length; i++) {
var li = document.createElement("li");
baseList.appendChild(li);
var header = document.createElement("h2");
header.textContent = fields[i] + ":";
li.appendChild(header);
if (report.length > 0) {
var table = document.createElement("table");
table.className += "wide";
li.appendChild(table);
var tr = document.createElement("tr");
table.appendChild(tr);
var td = document.createElement("td");
td.colSpan = report.length;
tr.appendChild(td);
tr = document.createElement("tr");
table.appendChild(tr);
var compare = "NeverEqual";
var count = 0;
td = null;
for (var j = 0; j < report.length; j++) {
if (compare == report[j][i]) {
count++;
td.colSpan = count;
if (compare != null)
td.style.backgroundColor = "#336";
} else {
count = 1;
compare = report[j][i];
td = document.createElement("td");
tr.appendChild(td);
td.textContent = report[j][i];
//td.colSpan = 1;
if (compare != null)
td.style.backgroundColor = "#333";
else {
td.style.backgroundColor = "#633";
}
}
}
}
}
space.style.height = "93%";
space.style.overflow = "auto";
}

Your not specifying explicit widths for the table cells so they'll be auto calculated based on their content and the fallback logic the browser / IE does. If you want to have a cell have a specific width apply either a class to it or set it's with property explicity, e.g.:
td.style.width = "50px";
Or
td.className = "myCell";
// and in css somewhere define the class
.myCell{
width: 50px;
}

Related

Dynamically created html table data not showing in order as expected

function CreateWeakHeader(name) {
var tr = document.createElement('tr');
var td = document.createElement('td');
td.classList.add("cal-usersheader");
td.style.color = "#000";
td.style.backgroundColor = "#7FFF00";
td.style.padding = "0px";
td.appendChild(document.createTextNode(name));
tr.appendChild(td);
var thh = document.createElement('td');
thh.colSpan = "31";
thh.style.color = "#FFFFFF";
thh.style.backgroundColor = "#7FFF00";
tr.appendChild(thh);
return tr;
}
function htmlTable(data, columns) {
var header = document.createElement("div");
header.classList.add("table-responsive");
var header2 = document.createElement("div");
header2.id = "calplaceholder";
header.appendChild(header2);
var header3 = document.createElement("div");
header3.classList.add("cal-sectionDiv");
header2.appendChild(header3);
if ((!columns) || columns.length == 0) {
columns = Object.keys(data[0]);
}
var tbe = document.createElement('table');
tbe.classList.add("table", "table-striped", "table-bordered");
var thead = document.createElement('thead');
thead.classList.add("cal-thead");
tbe.appendChild(thead);
var tre = document.createElement('tr');
for (var i = 0; i < columns.length; i++) {
var the = document.createElement('th');
the.classList.add("cal-toprow");
the.textContent = columns[i];
tre.appendChild(the);
}
thead.appendChild(tre);
var tbody = document.createElement('tbody');
tbody.classList.add("cal-tbody");
tbe.appendChild(tbody);
var week = 0;
//tbody.appendChild(CreateWeakHeader("Week " + week));
var tre = document.createElement('tr');
for (var j = 0; j < data.length; j++) {
if (j % 7 == 0) {
week++;
tbody.appendChild(CreateWeakHeader("Week " + week));
}
var thead = document.createElement('td');
thead.classList.add("ui-droppable");
thead.appendChild(data[j]);
tre.appendChild(thead);
tbody.appendChild(tre);
}
header3.appendChild(tbe);
document.body.appendChild(header);
}
$("#tb").click(function() {
var header = document.createElement("div");
header.innerHTML = "test";
var d = [header, header, header, header, header, header, header, header];
htmlTable(d, days);
});
var days = ['Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag', 'Zondag'];
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="tb">CreateTable</button>
I'm trying to order the data that I get from my server to match the columns of my table.
My table columns are days from Monday to Sunday. When my data has more than 7items it needs to separate with another td. The td shows me week 1 and when my data has more than 7 items it needs to separate again that shows week 2 etc.
Update
Im now using a snipped verdion of my code.
Hope someone can help me out with this.
Thank you
There's a few things going on in the code that are problematic.
An attempt to add the table cells to the row, and the row to the table, was made on each iteration of the for loop. That would have produced a lot of rows with single cells had it worked.
It didn't work because there was only ever a single instance of tre, the row variable. So that meant the line tbody.appendChild(tre); did nothing, since appendChild won't append an element that already has a parent element.
Because your data was an array of references to HTMLElements with parents, appending them using appendChild did nothing for the same reason.
I've amended the code below to take care of all of these situations.
Firstly, the code will append a clone of the data to the cell if it's an HTMLElement. I expect in your real code you won't need this, but for this example, why not? It then appends the cell to the row and continues to the next data element.
Secondly, when the data iterator is at 7, before it appends the "Week N" header, it appends a clone of the row, if it has cells on it.
Finally, after appending the clone of the row, the code will reset the row variable to a new instance of a tr element, with no cells.
I also made some variable name and formatting changes to your code just so I could more easily work with it.
function CreateWeakHeader(name) {
var tr = document.createElement('tr');
var td = document.createElement('td');
td.classList.add("cal-usersheader");
td.style.color = "#000";
td.style.backgroundColor = "#7FFF00";
td.style.padding = "0px";
td.appendChild(document.createTextNode(name));
tr.appendChild(td);
var thh = document.createElement('td');
thh.colSpan = "6"; // "31"; Why 31? A week has 7 days...
thh.style.color = "#FFFFFF";
thh.style.backgroundColor = "#7FFF00";
tr.appendChild(thh);
return tr;
}
function htmlTable(data, columns) {
var header = document.createElement("div");
header.classList.add("table-responsive");
var header2 = document.createElement("div");
header2.id = "calplaceholder";
header.appendChild(header2);
var header3 = document.createElement("div");
header3.classList.add("cal-sectionDiv");
header2.appendChild(header3);
if ((!columns) || columns.length == 0) {
columns = Object.keys(data[0]);
}
var tbe = document.createElement('table');
tbe.classList.add("table", "table-striped", "table-bordered");
var thead = document.createElement('thead');
thead.classList.add("cal-thead");
tbe.appendChild(thead);
var tre = document.createElement('tr');
for (var i = 0; i < columns.length; i++) {
var the = document.createElement('th');
the.classList.add("cal-toprow");
the.textContent = columns[i];
tre.appendChild(the);
}
thead.appendChild(tre);
var tbody = document.createElement('tbody');
tbody.classList.add("cal-tbody");
tbe.appendChild(tbody);
var week = 0;
//tbody.appendChild(CreateWeakHeader("Week " + week));
var tre = document.createElement('tr');
for (var j = 0; j < data.length; j++) {
if (j % 7 == 0) {
week++;
/* Major changes start here */
// if the row has cells
if (tre.querySelectorAll('td').length) {
// clone and append to tbody
tbody.appendChild(tre.cloneNode(true));
// reset table row variable
tre = document.createElement('tr');
}
// then append the Week header
tbody.appendChild(CreateWeakHeader("Week " + week));
}
var td = document.createElement('td');
td.classList.add("ui-droppable");
// Set the value of the cell to a clone of the data, if it's an HTMLElement
// Otherwise, make it a text node.
var value = data[j] instanceof HTMLElement ?
data[j].cloneNode(true) :
document.createTextNode(data[j]);
td.appendChild(value);
tre.appendChild(td);
}
// If the number of data elements is not evenly divisible by 7,
// the remainder will be on the row variable, but not appended
// to the tbody, so do that.
if (tre.querySelectorAll('td').length) {
tbody.appendChild(tre.cloneNode(true));
}
header3.appendChild(tbe);
document.body.appendChild(header);
}
$("#tb").click(function() {
var header = document.createElement("div");
header.innerHTML = "test";
var d = [header, header, header, header, header, header, header, header];
htmlTable(d, days);
});
var days = ['Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag', 'Zondag'];
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="tb">CreateTable</button>

Memory game board creation, javascript

Im trying to make a memory game in javascript, but im having problems with creating the board + adding an event handler(click) to the images that are going in the table data. heres the code snippet:
var board = document.getElementById("board");
var img = document.createElement("img");
var NUM_ROWS = 6;
var NUM_COLS = 6;
for (row = 0; row < NUM_ROWS; row++) {
var tr = document.createElement("tr");
for (col = 0; col < NUM_COLS; col++) {
var td = document.createElement("td");
var img = document.createElement("img");
tr.appendChild(td);
img.src = 'images/image0.png';
tr.appendChild(img);
}
board.appendChild(tr);
}
There are many ways to do this. One way that gives you a lot of flexibility is to build up a string version of the image element that has all the features that you need and insert it into your table cell element by setting td.innerHTML as follows:
function myclick(row,col) {
// handle the click here
}
var board = document.getElementById("board");
var NUM_ROWS = 6;
var NUM_COLS = 6;
for (var row = 0; row < NUM_ROWS; row++) {
var tr = document.createElement("tr");
for (col = 0; col < NUM_COLS; col++) {
var td = document.createElement("td");
var src = "images/image0.png";
var img = '<img src="'+src+'" onclick="myclick('+row+','+col+');">';
td.innerHTML = img;
tr.appendChild(td);
}
board.appendChild(tr);
}
In this case, the img element is created with the onclick function built in and will provide the row and column of the click to your click handling function.

How to get th when child td is clicked?

I trying to get the <th> content of the clicked <td> item.
here is the fiddle: http://jsfiddle.net/zrccq447/
the thing is, the <th> can have colspan 2 or 3, this is the point where I am stuck. this is my code
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var x = $('#headerx9 th:nth-child(' + (clicked_pos) + ')').text();
var xy = td.text();
alert(x);
});
i want x to be the <th> of clicked td. the problem is now that if you click on some td that shares the th with other tds, i am getting the wrong th.
appreciate any help
I've updated your JsFiddle with the answer found here: Finding a colSpan Header for one of the cells or td's is Spans
JsFiddle: http://jsfiddle.net/zrccq447/4/
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var x = $('#headerx9 th:nth-child(' + thLocator[clicked_pos] + ')').text();
var xy = td.text();
alert(x);
});
var thLocator = [], colCount = 1;
$('#table9').find('tr:first th').each(function () {
for (var i = 0; i < this.colSpan; i++) {
thLocator.push(colCount);
}
colCount++;
});
Following on from my comment you need to sum up the colspans (or default 1) for each TH until you get enough to match the column you desire:
http://jsfiddle.net/TrueBlueAussie/zrccq447/5/
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var cols = 0;
var $table = td.closest('table');
var $ths = $table.find('tr th');
for (var i = 1; i < $ths.length; i++) {
var $th = $ths.eq(i);
cols += ~~$th.attr('colspan') || 1;
if (cols >= clicked_pos) {
var x = $th.text();
alert(x);
break;
}
}
});
I tried to keep it generic, so it finds the appropriate table and headers on the fly.
One approach is to get store a reference to each TH, in order, in an array and call the text from the array based on the location of the td.
var thholder = $('table th'),
th = [];
for(var i = 0; i < thholder.length; i++) {
var thi = $(thholder[i]);
for(var j = 0; j < (thi.attr('colspan') || 1); j++) {
th.push(thi);
}
}
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
alert(th[clicked_pos].text());
});
http://jsfiddle.net/zrccq447/3/
This code is not optimised, but shows the approach:
Loop through all the TH in the table.
If the TH does not have the attribute 'colspan', then set the attribute to a value of 1.
Create a loop for each value of colspan and save a reference to the current TH in the array.
When you click on a TD, get it's clicked position and retrieve the text of the TH at that position in the array and alert it :)

How to check value of table td?

I am trying to create mine field game. "I am very new to Js".
What I have done so far:
var level = prompt("Choose Level: easy, medium, hard");
if (level === "easy") {
level = 3;
} else if (level === "medium") {
level = 6;
} else if (level === "hard") {
level = 9;
}
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
var tblBody = document.createElement("tbody");
for (var i = 1; i <= 10; i++) {
var row = document.createElement("tr");
document.write("<br/>");
for (var x = 1; x <= 10; x++) {
var j = Math.floor(Math.random() * 12 + 1);
if (j < level) {
j = "mined";
} else {
j = "clear";
}
var cell = document.createElement("td");
var cellText = document.createTextNode(j + " ");
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "2");
So I create here 2d table and enter 2 random values in rows and columns (mined or clear).
Where I am stuck is:
Check if td = mined it dies otherwise open the box(td) etc.
How do I assign value of td? I mean how can I check which value(mined/clear) there is in the td which is clicked?
Ps: Please don't write the whole code:) just show me the track please:)
Thnx for the answers!
Ok! I came this far.. But if I click on row it gives sometimes clear even if I click on mined row or vice versa!
// create the table
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
tbl.setAttribute('id','myTable');
var tblBody = document.createElement("tbody");
//Create 2d table with mined/clear
for(var i=1;i<=10;i++)
{
var row = document.createElement("tr");
document.write("<br/>" );
for(var x=1;x<=10;x++)
{
var j=Math.floor(Math.random()*12+1);
if(j<level)
{
j = "mined";
}
else{
j = "clear";
}
var cell = document.createElement("td");
var cellText = document.createTextNode(j + "");
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "2");
//Check which row is clicked
window.onload = addRowHandlers;
function addRowHandlers() {
var table = document.getElementById("myTable");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row)
{
return function() {
var cell = row.getElementsByTagName("td")[0];
var id = cell.innerHTML;
if(id === "mined")
{
alert("You died");
}else
{
alert("clear");
}
};
}
currentRow.onclick = createClickHandler(currentRow);
}
}
I think I do something wrong with giving the table id "myTable"..
Can you see it?
Thank you in advance!
So, the idea would be:
assign a click event to each td cell:
td.addEventListener('click', mycallback, false);
in the event handler (callback), check the content of the td:
function mycallback(e) { /*e.target is the td; check td.innerText;*/ }
Pedagogic resources:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td?redirectlocale=en-US&redirectslug=HTML%2FElement%2Ftd
https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener
JavaScript, getting value of a td with id name

Combine HTML Table Rows with Javascript

Is there an easy way to combine rows in an HTML table where the first column is the same? I basically have a table set up like:
<table>
<tr><td>test</td><td>12345</td><td>12345</td><tr>
<tr><td>test</td><td>12345</td><td>12345</td><tr>
<tr><td>test2</td><td>12345</td><td>12345</td><tr>
<tr><td>test</td><td>12345</td><td>12345</td><tr>
<tr><td>test2</td><td>12345</td><td>12345</td><tr>
</table>
and I want it to generate:
<table>
<tr><td>test</td><td>37035</td><td>37035</td><tr>
<tr><td>test2</td><td>24690</td><td>24690</td><tr>
</table>
using jQuery:
var map = {};
$('table tr').each(function(){
var $tr = $(this),
cells = $tr.find('td'),
mapTxt = cells.eq(0).text();
if(!map[mapTxt]){
map[mapTxt] = cells;
} else {
for(var i=1, l=cells.length; i<l; i++){
var cell = map[mapTxt].eq(i);
cell.text(parseInt(cell.text()) + parseInt(cells[i].text()));
}
$tr.remove();
}
});
this is a "dumb" script -- no error handling for cases like different number of cells, fields being non-numeric, etc. Add those if necessary.
Also, depending on how it's generated, it's better to do this server-side.
Here's a plain JavaScript version.
window.onload = function() {
var table = document.getElementById('mytable');
var tr = table.getElementsByTagName('tr');
var combined = Array();
for (i = 0; i < tr.length; i++) {
var td = tr[i].getElementsByTagName('td');
var key = td[0].innerText;
if (!combined[key]) {//if not initialised
combined[key] = Array();
for (j = 0; j < td.length - 1; j++) combined[key][j] = 0;
}
for (j = 0; j < td.length - 1; j++)
combined[key][j] += parseInt(td[j + 1].innerText);
}
while (table.hasChildNodes()) table.removeChild(table.lastChild);
var tbody = document.createElement('tbody');//needed for IE
table.appendChild(tbody);
for (var i in combined) {
tr = document.createElement('tr');
tbody.appendChild(tr);
td = document.createElement('td');
td.innerText = i;
tr.appendChild(td);
for (j = 0; j < combined[i].length; j++) {
td = document.createElement('td');
td.innerText = combined[i][j];
tr.appendChild(td);
}
}
}
This will work on tables with any number of rows and any number of cells. I suppose you want to make the sum for every column, that's what this script does.
And as cwolves mentioned, it is more logical to do this serverside. Users that have JS disabled will see the not so clean uncombined table.

Categories