I dynamically add data to table from a Javascript object.
I have a code that ends up something like this:
<table>
<tr>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
</tr>
</table>
I want table borders in each row even if the tds don't exist. So basically for the example in the code I want a 3x3 table with borders.
Is this possible without actually making empty tds in each row?
You can:
Modify the original JS so that it generates colspan attributes (<td colspan="3"> will be as wide as 3 <td>'s; Of course you will lose the grid symmetry.
If your table cells each have the same fixed width, you could use a background-image on the table.
You could wrap up a little script to complete the table, cf:
var table = document.getElementsByTagName('table')[0];
function normalizeTable() {
var trs = table.getElementsByTagName('tr'),
len = trs.length, max = 0, td;
// first we search for the longest table row in terms of # of children
for (var i = len; i--;) {
if (trs[i].children.length > max)
max = trs[i].children.length;
}
// now we can fill the other rows
for (var j = len; j--;) {
while (trs[j].children.length < max) {
td = document.createElement('td');
trs[j].appendChild(td);
}
}
}
normalizeTable();
EDITED
In my opinion, you have to add only a little CSS and insert all TD (empty):
table {
border-style: solid;
border-width: 1px;
border-collapse: separate;
empty-cells: show;
}
td {
border-style: solid;
border-width: 1px;
}
<table>
<tr>
<td>1</td>
<td></td> <!-- empty -->
<td></td> <!-- empty -->
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td></td> <!-- empty -->
</tr>
</table>
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 months ago.
Improve this question
I have a table with multiple columns, one column named: ‘Type’. The values in Type column could be: 1 or 2.
I want to replace the value “1” to “Information” and the value “2” to “Problem” in every row with jQuery, how can I do that?
Here in this demo you'll find a function transformTableData() that takes the table existing in the document and will:
find where is located the field having as header the string "Type";
loop through all its rows and change the value of the corresponding field as the result coming out of the map defined on top. So according to the default map I defined, if the field value is '1' it will be transformed to 'Information' and if the value is '2' it will be transformed to 'Problem';
If there's no corresponding value in the map, the value will be untouched;
The function runs when you click the button on the bottom of the page. Of course the same function could be called on document ready.
function transformTableData(){
const map = {
'1' : 'Information',
'2' : 'Problem',
}
const typeHeaderCell = $('table thead tr th:contains(Type)');
const typeHeaderIndex = $(typeHeaderCell).index();
$('table tbody tr').each((i, row)=>{
const rowCell = $(row).find(`td:nth-child(${typeHeaderIndex+1})`);
const value = rowCell.text();
rowCell.text( map?.[value] );
});
}
table, tr, th, td{
border: solid 1px black;
padding: 1rem;
}
button{
margin-top: 1rem;
padding: 1rem;
font-size: 1.25rem;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Column1</th>
<th>Column2</th>
<th>...</th>
<th>Type</th>
<th>...</th>
<th>ColumnN</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td>1</td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td>2</td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td>INVALID</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<button onclick="transformTableData();">Transform Table Data</button>
There are many ways to achieve something like this. Here is one example. It first looks for the index by comparing the text of each cell in the table header. then it gets all cells in the table body with the index in each table row and replaces the content if it is "1" or "2". There are for sure even shorter or faster methods.
// Find index of column with "Type"
let index = -1;
let th = $('#myTable thead tr th');
for (let i=0; i<th.length; i++) {
if ($(th[i]).text() == 'Type') {
index = i;
break;
}
}
// If index is greater then -1 we found the column
if (index > -1) {
// Get all the table cells in each row at the specific index (need to add +1 to the index)
let td = $('#myTable tbody tr td:nth-child(' + (index+1) + ')');
for (let i=0; i<td.length; i++) {
// Compare content and replace it
if ($(td[i]).text() == '1') {
$(td[i]).text('Information');
}
else if ($(td[i]).text() == '2') {
$(td[i]).text('Problem');
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable">
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>1</td>
<td>John</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>Maria</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
<td>Walter</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>Julia</td>
</tr>
</tbody>
</table>
I have a table with cells that are not contentEditable. However, using a JavaScript loop or function, I would like to make them so.
I understand that it is very simple to do this manually for each cell, and this would probably be easier for a table with only a few cells, but I would like to quicken this process with a loop/function for the table could become much larger, and the time spent manually setting each cell to be contentEditable would be tedious.
Below is a quick example that displays a table calculator, un-editable at present. But using a loop or function, I'd like to make every cell in the right column set to .contentEditable = true in the DOM. I imagine that the parameters would look something like (var i = 0; l != rows.length; i < l; i+2), but I'm struggling with what the statements following the argument would have to be for the loop/function to work. Any help would be much appreciated!
function myFunction() {
var jack2 = document.getElementById("jack").innerText;
var john2 = document.getElementById("john").innerText;
var joe2 = document.getElementById("joe").innerText;
var total2 = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt(joe2) || 0);
document.getElementById("total").innerHTML = total2;
}
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid gray;
border-collapse: collapse;
font-family: Arial;
margin: 5px;
}
<table>
<caption>Weight Calculator</caption>
<tr class="cell">
<th>Person</th>
<th>Weight (kg)</th>
</tr>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()">1</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()">2</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()">3</td>
</tr>
<tr class="cell">
<td>Total</td>
<td id="total"></td>
</tr>
</table>
Get all cell in the tabel that have a left neigbour (the header is not effected because there are th and not td). Add to each of these cells your attribute.
Edited: For getting the totalsum add an eventlistener on each td that calls the calc-function if the content changes.
function myFunction() {
let weightCells = document.querySelectorAll("table tr:not(:last-child) td ~ td");
weightCells.forEach(td => {
td.setAttribute('contentEditable', true);
td.addEventListener ("change", calcSum());
});
}
function calcSum() {
let sum=0;
let weightCells = document.querySelectorAll("table tr td ~ td");
let count = weightCells.length-1;
for (i=0; i<count; i++) {
sum += parseInt(weightCells[i].innerHTML) || 0;
}
weightCells[count].innerHTML = sum;
}
myFunction();
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid gray;
border-collapse: collapse;
font-family: Arial;
margin: 5px;
}
<table>
<caption>Weight Calculator</caption>
<tr class="cell">
<th>Person</th>
<th>Weight (kg)</th>
</tr>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()">1</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()">2</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()">3</td>
</tr>
<tr class="cell">
<td>Total</td>
<td id="total"></td>
</tr>
</table>
You can select the whole table, then use querySelectorAll to get all rows then for each rows change the contenteditable for the second td like this
codepen
let table = document.getElementById('table')
let rows = table.querySelectorAll('tr')
rows.forEach(row => {
let tds = row.querySelectorAll('td')
// all the cells of the row
if (tds.length > 0) { // if it is not the header
tds[1].contentEditable = true
// change the contenteditable
}
})
(you need to add an id to your table in case you have more than one table)
<table id="table">
...
</table>
I've been wrestling with this for a while. I have a table which is automatically generated based on some JSON data, which may vary. I'd like to merge neighbouring cells in the first column which have the same value, e.g. "fish" and "bird" in this table:
<table>
<tr>
<td>fish</td>
<td>salmon</td>
</tr>
<tr>
<td>fish</td>
<td>cod</td>
</tr>
<tr>
<td>fish</td>
<td>plaice</td>
</tr>
<tr>
<td>bird</td>
<td>robin</td>
</tr>
<tr>
<td>bird</td>
<td>crow</td>
</tr>
</table>
I don't want to use any libraries ideally, just pure JS.
This is what I would like it to look like:
table, tr, td {
border: solid 1px black;
}
<table>
<tr>
<td rowspan="3">fish</td>
<td>salmon</td>
</tr>
<tr>
<td>cod</td>
</tr>
<tr>
<td>plaice</td>
</tr>
<tr>
<td rowspan="2">bird</td>
<td>robin</td>
</tr>
<tr>
<td>crow</td>
</tr>
</table>
I've been finding different ways to identify the different values and their frequency and then change the rowspan to the right number and subsequently deleting the the other cells but these all broke down in differing use cases.
This is what I have so far:
let table = document.querySelector('table');
let rowCount = 1;
for (let i = 0; i < (table.rows.length - 1); i++) {
if (table.rows[i].cells[0].innerHTML === table.rows[i + 1].cells[0].innerHTML) {
rowCount++;
} else if (rowCount !== 1) {
table.rows[i].cells[0].setAttribute('rowspan', rowCount);
for (let j = (i - rowCount + 1); j < rowCount; j++) {
table.rows[j].cells[0].remove();
};
rowCount = 1;
};
};
table, tr, td {
border: solid 1px black;
}
<table>
<tr>
<td>fish</td>
<td>salmon</td>
</tr>
<tr>
<td>fish</td>
<td>cod</td>
</tr>
<tr>
<td>fish</td>
<td>plaice</td>
</tr>
<tr>
<td>bird</td>
<td>robin</td>
</tr>
<tr>
<td>bird</td>
<td>crow</td>
</tr>
</table>
This isn't doing what I want at all but I feel I'm really close! It's trying to count the number of (first column) cells for which the one below has the same value, assigning this number to the rowspan of the last relevant cell and then deleting the subsequent cells before looping back to catch the rest of them. I'd love for my final code to be a variation of this, so can someone show me where I'm going wrong please?
You were indeed pretty close!
A way to simplify quite a bit is to keep a reference to the current "header" cell, i.e. the one you want to increase the rowspan of. That way you don't have to deal with indexes at all, yielding a very straightforward algorithm:
For each row
Set firstCell to the row's first cell
If this is the first row OR firstCell's text is different from headerCell's text
Set headerCell to firstCell
Otherwise
Increase headerCell's rowSpan by 1
Remove firstCell
In JavaScript, it looks like this:
const table = document.querySelector('table');
let headerCell = null;
for (let row of table.rows) {
const firstCell = row.cells[0];
if (headerCell === null || firstCell.innerText !== headerCell.innerText) {
headerCell = firstCell;
} else {
headerCell.rowSpan++;
firstCell.remove();
}
}
table, tr, td {
border: solid 1px black;
}
<table>
<tr>
<td>fish</td>
<td>salmon</td>
</tr>
<tr>
<td>fish</td>
<td>cod</td>
</tr>
<tr>
<td>fish</td>
<td>plaice</td>
</tr>
<tr>
<td>bird</td>
<td>robin</td>
</tr>
<tr>
<td>bird</td>
<td>crow</td>
</tr>
</table>
I have set markup HTML ON in my pl/sql script. I'm running a select query whose output by default as a table I'm writing to a html file.
I want to highlight a few rows in that table based on the value of a column. For that I'm trying to set a CSS class for those rows.
From CSS, I can only access table's <th> and <td> in general. Kindly suggest how this can be done.
$(function() {
var val = ['X', 'Z'];
for (var i = 0; i < val.length; i++) {
$('table tr td:contains(' + val[i] + ')').each(function() {
$(this).closest('tr').addClass('highlight');
});
}
});
.highlight td {
border: 1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>A</td>
<td>X</td>
</tr>
<tr>
<td>A</td>
<td>V</td>
</tr>
<tr>
<td>X</td>
<td>B</td>
</tr>
<tr>
<td>Z</td>
<td>B</td>
</tr>
</table>
If you have a specific range of values, so as to get tr highlighted, You can use something like this. I don't know how to exactly style the 'tr' to make it highlighted.
Am trying to add a :before to a td element in my table with content same as the value as the th in the same column, i got to the point where i can change the value of the td but im stuck at adding the :before, here is my code:
function myFunction() {
var rows = document.getElementsByTagName("table")[0].rows;
var last = rows[0];
var first = rows[1];
for (i = 0; i < 2; i++) {
var cell = last.cells[i];
var value = cell.innerHTML;
alert(value);
first.cells[i].innerHTML = value;
}
}
<table>
<thead>
<tr>
<th>aa</th>
<th>bb</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
</tbody>
</table>
<button onclick="myFunction()">Test</button>
You can't add :before to element with JavaScript. But you can do it with CSS:
td:before {
content: attr(data-content);
}
<td data-content="content for :before">
actual content
</td>
And then just change data-content attribute on td with JavaScript.