Highlighting a Table - javascript

So I'm trying to figure out the best and easiest way to highlight a selection of cells from a table.
#A1lnk, #B1lnk {cursor: pointer;}
<table border="1">
<tr>
<th colspan="2"><a id='A1lnk'>A1</a></th><th colspan="2"><a id='B1lnk'>B1</a></th>
</tr>
<tr>
<td>A1-1</td><td>A1-2</td><td>B1-1</td><td>B1-2</td>
</tr>
<tr>
<td>A1-3</td><td>A1-4</td><td>B1-3</td><td>B1-4</td>
</tr>
<tr>
<td>A1-5</td><td>A1-6</td><td>B1-5</td><td>B1-6</td>
</tr>
<tr>
<th colspan="2"><a id='C1lnk'>C1</a></th><th colspan="2"><a id='D1lnk'>D1</a></th>
</tr>
<tr>
<td>C1-1</td><td>C1-2</td><td>D1-1</td><td>D1-2</td>
</tr>
<tr>
<td>C1-3</td><td>C1-4</td><td>D1-3</td><td>D1-4</td>
</tr>
<tr>
<td>C1-5</td><td>C1-6</td><td>D1-5</td><td>D1-6</td>
</tr>
<tr>
<th colspan="2"><a id='E1lnk'>E1</a></th><th colspan="2"><a id='F1lnk'>F1</a></th>
</tr>
<tr>
<td>E1-1</td><td>E1-2</td><td>F1-1</td><td>F1-2</td>
</tr>
<tr>
<td>E1-3</td><td>E1-4</td><td>F1-3</td><td>F1-4</td>
</tr>
<tr>
<td>E1-5</td><td>E1-6</td><td>F1-5</td><td>F1-6</td>
</tr>
</table>
You can see I have essentially got two columns, A1 and B1. The contents are very simple but suffice to say the actual contents will not be that simple.
I want to be able to click B1 and all the cells below it are highlighted, highlights are the easy part, actually selecting the correct cells is much harder.
I will have multiple other small tables adding C1, D1, E1, F1, G1, H1 etc. So there could be a few extra but only ever in columns of two. They will cascade in the rows and so still be part of the parent table but I'm just trying to figure out the best way to go about it, since the table creates them in rows and not columns.

I tried something like you said, however the code gone very long, that's why I have removed some rows.
var a1lnk = document.getElementById('A1lnk');
var a2lnk = document.getElementById('B1lnk');
var a3lnk = document.getElementById('C1lnk');
var a1 = document.getElementById('a1');
var a2 = document.getElementById('a2');
var c1 = document.getElementById('c1');
var c2 = document.getElementById('c2');
function unhighlight () {
b1.removeAttribute('h');
b2.removeAttribute('h');
a1.removeAttribute('h');
a2.removeAttribute('h');
c1.removeAttribute('h');
c2.removeAttribute('h');
}
var b1 = document.getElementById('b1');
var b2 = document.getElementById('b2');
function highlightA () {
unhighlight();
a1.setAttribute('h', true);
a2.setAttribute('h', true);
}
function highlightB () {
unhighlight();
b1.setAttribute('h', true);
b2.setAttribute('h', true);
}
function highlightC () {
unhighlight();
c1.setAttribute('h', true);
c2.setAttribute('h', true);
}
a1lnk.onclick = highlightA;
a2lnk.onclick = highlightB;
a3lnk.onclick = highlightC;
#A1lnk, #B1lnk, #C1lnk {cursor: pointer;}
td[h] {
background-color: orange;
color: #fff;
}
<table border="1">
<tr>
<th colspan="2"><a id='A1lnk'>A1</a></th><th colspan="2"><a id='B1lnk'>B1</a></th>
</tr>
<tr>
<td id="a1">A1-1</td><td id="a2">A1-2</td><td id="b1">B1-1</td><td id="b2">B1-2</td>
</tr>
<tr>
<th colspan="2"><a id='C1lnk'>C1</a></th>
</tr>
<tr>
<td id="c1">C1-1</td><td id="c2">C1-2</td>
</tr>
</table>
Hope, this should work for you.

You should use a class for header instead of different ids. Then on click of header get it's index. Using this index you can easily select the cells below it using nextUntil() method and :nth-child pseudo selector and highlight them like following.
$('.header').click(function() {
var index = $(this).parent().index(),
a = index * 2 + 1,
b = a + 1;
$('.highlight').removeClass('highlight');
var tr = $(this).closest('tr').nextUntil(':has(th)')
tr.find('td:nth-child(' + a + '), td:nth-child(' + b + ')').addClass('highlight');
});
.header {
cursor: pointer;
}
.highlight {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th colspan="2"><a class="header">A1</a></th>
<th colspan="2"><a class="header">B1</a></th>
</tr>
<tr>
<td>A1-1</td>
<td>A1-2</td>
<td>B1-1</td>
<td>B1-2</td>
</tr>
<tr>
<td>A1-3</td>
<td>A1-4</td>
<td>B1-3</td>
<td>B1-4</td>
</tr>
<tr>
<td>A1-5</td>
<td>A1-6</td>
<td>B1-5</td>
<td>B1-6</td>
</tr>
<tr>
<th colspan="2"><a class="header">C1</a></th>
<th colspan="2"><a class="header">D1</a></th>
</tr>
<tr>
<td>C1-1</td>
<td>C1-2</td>
<td>D1-1</td>
<td>D1-2</td>
</tr>
<tr>
<td>C1-3</td>
<td>C1-4</td>
<td>D1-3</td>
<td>D1-4</td>
</tr>
<tr>
<td>C1-5</td>
<td>C1-6</td>
<td>D1-5</td>
<td>D1-6</td>
</tr>
<tr>
<th colspan="2"><a class="header">E1</a></th>
<th colspan="2"><a class="header">F1</a></th>
</tr>
<tr>
<td>E1-1</td>
<td>E1-2</td>
<td>F1-1</td>
<td>F1-2</td>
</tr>
<tr>
<td>E1-3</td>
<td>E1-4</td>
<td>F1-3</td>
<td>F1-4</td>
</tr>
<tr>
<td>E1-5</td>
<td>E1-6</td>
<td>F1-5</td>
<td>F1-6</td>
</tr>
</table>

Related

Group column with the same subheader name in datatable using Javascript/jQuery

I have a table like this
In which I have different city where we have demand-supply of different products.
Now what I want as here demand is different for all the products However supply is the same on all of three product, so I want that table looks like in this manner.
What I want to do is I want only to show the supply column once in the last of the table. This has to be done dynamically as in the future we have multiple products
Can anyone help me with this?
What the code below does is:
Identify the positions of the "Supply"'s and store them in ind array, in this case will be [3, 5, 7]
Loops through ind except for the last element 7(as one "Supply" will be left) and hide all td's; $("td:nth-child("3"), $("td:nth-child("5")
The "Demand"s that precede each of these elements will be assigned two spaces.
let ind = [];
$("td:contains('Supply')").each(function (index) {
ind.push($(this).index() + 1);
});
$(".hide").on("click", function () {
for (let i = 0; i < ind.length - 1; i++) {
let el = $("td:nth-child(" + ind[i] + ")");
el.prev().attr("colspan", "2");
el.hide();
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<th>City</th>
<th colspan="2">Product 1</th>
<th colspan="2">Product 2</th>
<th colspan="2">Product 3</th>
</tr>
<tr>
<td></td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
</tr>
<tr>
<td>City 1</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 2</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 3</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 4</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
</table>
<button class="hide">Hide</button>

Get the value of the next table cell onclick javascript

I am trying to get the value of the cell right of the cell where i click.
But right now I get the value of the cell I want, but I can click any cell in that row and get the desired value. But it should only be possible with the first column. So I click the any cell in the first column and I wanna get it's next neighbour cell value.
document.querySelector("#tableEventListId").addEventListener("click",event => {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
Any help?
You can use nextElementSibling
document.getElementById('table1').onclick = function(event){
//REM: Target
var tElement = event.target;
if(
//REM: Only cells (=<td>)
tElement.tagName === 'TD' &&
//REM: Only first column cells
tElement.parentNode.firstElementChild === tElement
){
//REM: Next Elementsibling of Target or Null
var tNext = tElement.nextElementSibling;
if(tNext){
console.log('TD: ', tElement.textContent);
console.log('Next: ', tElement.nextElementSibling.textContent)
}
}
}
table, td{
border: 1px solid black
}
<table id = 'table1'>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1</td>
<td>B1</td>
<td>C1</td>
</tr>
<tr>
<td>A2</td>
<td>B2</td>
<td>C2</td>
</tr>
<tr>
<td>A3</td>
<td>B3</td>
<td>C3</td>
</tr>
</tbody>
</table>
There is no HTML, so I can assume it's something like
<table border="1">
<tr>
<td class="first-column">1.1 (click here)</td>
<td>1.2</td>
<td>1.3</td>
</tr>
<tr>
<td class="first-column">2.1 (click here)</td>
<td>2.2</td>
<td>2.3</td>
</tr>
</table>
According to this HTML, you can try
const firstColumns = document.querySelectorAll(".first-column");
for (let i = 0; i < firstColumns.length; i++) {
firstColumns[i].addEventListener("click", function(event) {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
});
}
Have a look https://jsfiddle.net/vyspiansky/k2toLd8w/
I would recommend you to a an event on every td element of the table. Then use nextElementSibling to get a next cell.
Look code snippet to see the example.
const cells = document.querySelectorAll('#tableEventListId td');
cells.forEach(cell => cell.onclick = function(){
const nextCell = cell.nextElementSibling;
if (nextCell)
alert(nextCell.innerHTML);
})
<table id="tableEventListId">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>11</td>
<td>22</td>
<td>33</td>
<td>44</td>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
<td>444</td>
</tr>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
</table>
If you want it to work only for cells at first column change the selector to #tableEventListId td:first-child.

Show value in textarea if checkbox is true

I have a table with four columns Name, Age, Country and a checkbox. If the checkbox is clicked(true) the name value of the row is showed in a textarea.
I am not really sure how I can realise that.
A row:
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
if the checkbox is true the value "James" should be shown in a textarea.
Thank you all.
I believe you need to do this for multiple rows in a table.
First select all the checkboxes with Document.querySelectorAll() to attach the event (click) to all the checkboxes.
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
Inside the event (click) handler function target all the checked checkboxes to loop through them to get the relevant names using Array.prototype.map():
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Also it is not good practice to mix up th and td inside of the same tr element. You should place th inside of a thead and td inside of tbody element:
var cb = document.querySelectorAll('input[type=checkbox]');
cb.forEach(function(ck){
ck.addEventListener('click', function(el){
var checked = document.querySelectorAll(':checked');
var tArea = document.getElementById('myText');
tArea.value = Array.from(checked).map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
//or using spread syntax
//tArea.value = [...checked].map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
});
});
table, th, td {
border: 1px solid black;
}
<table>
<thead>
<tr>
<th>Sl</th>
<th>Name</th>
<th>No</th>
<th>Country</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">1</td>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td scope="row">2</td>
<td>John</td>
<td>15</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr>
</tbody>
</table>
<textarea id="myText"></textarea>
Try this:
[...document.querySelectorAll("input[type='checkbox']")].forEach(function (v){
v.addEventListener("change", function(){
document.querySelector("textarea").value = (this).checked ? (this).parentElement.parentElement.querySelector("td").innerHTML:'';
})});
<table>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea></textarea>
Few javascript lines would be ok for you need.
let input = document.querySelector('input');
input.addEventListener('change', e=> {
if(e.target.checked == true){
// retreive tags
let name = document.querySelector('.name');
let textarea = document.querySelector('.textarea');
// insert data
textarea.innerText += name.innerText
}
})
<table>
<tr>
<th scope="row">1</th>
<td class="name">James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea class="textarea"></textarea>
Since your table can have multiple rows, where each can have the checkbox set or not, the textarea could get zero, one or more names.
So you would need to listen the change event, and then iterate the rows to collect the names, to finally set the value of the textarea:
let textarea = document.querySelector("textarea");
let table = document.querySelector("table");
table.addEventListener("change", function (e) {
let names = [];
for (let row of table.rows) {
if (row.querySelector("input[type=checkbox]").checked) {
names.push( row.children[1].textContent);
}
}
textarea.value = names.join("\n");
});
<table><tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr><tr>
<th scope="row">2</th>
<td>Lucy</td>
<td>14</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr></table>
<textarea></textarea>

Create select based on specific column data - using javascript

I am creating a table where in it has too many data and I want to put select option and just filter it, I already got the filter thing in the table using select, my question is how can I not manually add options to the select?
for example I have a column of dates containing 5 - 01-12-19 , 2 - 01-13-19 and 10 - 01-14-19 the said dates need to be the one in the options, and should only display 3 dates which is 01-12-19,01-13-19,01-14-19, the thing with manually adding options is not the best option because the column of dates are updated day by day.
<select>
<option></option>
</select>
<table border="2">
<thead>
<tr>
<th>Name</th>
<th>Dates</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>01-12-19</td>
</tr>
<tr>
<td>Jas</td>
<td>01-12-19</td>
</tr>
<tr>
<td>sam</td>
<td>01-12-19</td>
</tr>
<tr>
<td>James</td>
<td>01-12-19</td>
</tr>
<tr>
<td>luke</td>
<td>01-13-19</td>
</tr>
<tr>
<td>lucas</td>
<td>01-13-19</td>
</tr>
<tr>
<td>laus</td>
<td>01-13-19</td>
</tr>
<tr>
<td>cals</td>
<td>01-13-19</td>
</tr>
<tr>
<td>miya</td>
<td>01-14-19</td>
</tr><tr>
<td>lesley</td>
<td>01-14-19</td>
</tr>
</tbody>
</table>
I expect that using javascript the options will automatically fillout by the available dates but will only display in option as one even if there are 10 dates that are the same.
Assuming you're just trying to populate your select option with one of the columns then filter the below table every-time it changes, something like this will work.
const table = document.getElementById('myTable');
const trs = table.querySelectorAll('tbody tr');
const getAllDatesInTable = () => {
const table = document.getElementById('myTable');
const trs = table.querySelectorAll('tbody tr');
const dates = [];
trs.forEach( tr => {
const date = tr.querySelector('td:last-child').innerText;
if (!dates.includes(date)) {
dates.push(date);
}
});
return dates;
};
const dates = getAllDatesInTable();
const select = document.getElementById('dateFilter');
select.innerHTML = dates.map( d => `<option value=${d}>${d}</option>`);
select.onchange = (e) => {
const selection = e.target.value;
trs.forEach( tr => {
tr.style.display = '';
const date = tr.querySelector('td:last-child').innerText;
if (date !== selection) {
tr.style.display = 'none';
}
});
};
<select id="dateFilter">
<option></option>
</select>
<table border="2" id="myTable">
<thead>
<tr>
<th>Name</th>
<th>Dates</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>01-12-19</td>
</tr>
<tr>
<td>Jas</td>
<td>01-12-19</td>
</tr>
<tr>
<td>sam</td>
<td>01-12-19</td>
</tr>
<tr>
<td>James</td>
<td>01-12-19</td>
</tr>
<tr>
<td>luke</td>
<td>01-13-19</td>
</tr>
<tr>
<td>lucas</td>
<td>01-13-19</td>
</tr>
<tr>
<td>laus</td>
<td>01-13-19</td>
</tr>
<tr>
<td>cals</td>
<td>01-13-19</td>
</tr>
<tr>
<td>miya</td>
<td>01-14-19</td>
</tr><tr>
<td>lesley</td>
<td>01-14-19</td>
</tr>
</tbody>
</table>

universal javascript selector to interact on all html element

I started on that http://jsfiddle.net/DRFBG/
And if I add tables so mytable1, mytable2,...
<table id="mytable1" border="1">
<tr><th>Column1</th><th>Column2</th><th>Column3</th><th>Column4</th></tr>
<tr class="data"><td>1st</td><td>1.1</td><td></td><td>1</td></tr>
<tr class="data"><td>2nd</td><td>2.01</td><td></td><td>2</td></tr>
<tr class="data"><td>3rd</td><td>3.001</td><td></td><td>3</td></tr>
<tr class="data"><td>4th</td><td>4.01</td><td></td><td>4</td></tr>
</table>
<table id="mytable2" border="1">
<tr><th>Column1</th><th>Column2</th><th>Column3</th><th>Column4</th></tr>
<tr class="data"><td>1st</td><td>1.1</td><td>1</td><td></td></tr>
<tr class="data"><td>2nd</td><td>2.01</td><td>2</td><td></td></tr>
<tr class="data"><td>3rd</td><td>3.001</td><td>3</td><td></td></tr>
<tr class="data"><td>4th</td><td>4.01</td><td>4</td><td></td></tr>
</table>
How could I uniform my javascript code for all tables?
I've already tried passing by table[div^=mytable]*, but the problem is the second selector in the function.
So any ideas please? Thank you? Sorry for my english
By the way, the code is to remove th with empty td for each table
$('#mytable2 th').each(function(i) {
var remove = 0;
var tds = $(this).parents('table').find('tr td:nth-child(' + (i + 1) + ')')
tds.each(function(j) { if (this.innerHTML == '') remove++; });
if (remove == ($('#mytable2 tr').length - 1)) {
$(this).hide();
tds.hide();
}
});
One approach is, selecting tables first and get their id and after that, doing the approach of http://jsfiddle.net/DRFBG/ on each of them like the following:
$('table').each(function()
{
var tb_id = $(this).attr('id');
$('#'+tb_id+' th').each(function(i) {
var remove = 0;
var tds = $(this).parents('table').find('tr td:nth-child(' + (i + 1) + ')')
tds.each(function(j) { if (this.innerHTML == '') remove++; });
if (remove == ($('#'+tb_id+' tr').length - 1)) {
$(this).hide();
tds.hide();
}
});
});
Here is the working jsfiddle
To select all on your page you can use "table" selector.
So you'd need to use $('table2 th') instead of $('#mytable2 th')
One possible solution would be to loop through each column of each table, then check if there are any non-empty cells. If there is not, then you can safely remove() all the td and th within that column.
Note that the removal needs to be done last, otherwise it will affect the indexing of the following columns. You can do that by simply marking the cells to be removed with a class, and then selecting that class once all loops complete. Try this:
$('table').each(function() {
var $table = $(this);
var rows = $table.find('tr').length - 1; // -1 to account for the headings
$table.find('th').each(function(i, th) {
var $empty = $table.find(`td:nth-child(${i + 1}):empty`);
if ($empty.length == rows)
$empty.add(this).addClass('to-remove');
})
$table.find('.to-remove').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="mytable1" border="1">
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
<th>Column4</th>
</tr>
<tr class="data">
<td>1st</td>
<td>1.1</td>
<td></td>
<td>1</td>
</tr>
<tr class="data">
<td>2nd</td>
<td>2.01</td>
<td></td>
<td>2</td>
</tr>
<tr class="data">
<td>3rd</td>
<td>3.001</td>
<td></td>
<td>3</td>
</tr>
<tr class="data">
<td>4th</td>
<td>4.01</td>
<td></td>
<td>4</td>
</tr>
</table>
<table id="mytable2" border="1">
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
<th>Column4</th>
</tr>
<tr class="data">
<td>1st</td>
<td>1.1</td>
<td>1</td>
<td></td>
</tr>
<tr class="data">
<td>2nd</td>
<td>2.01</td>
<td>2</td>
<td></td>
</tr>
<tr class="data">
<td>3rd</td>
<td>3.001</td>
<td>3</td>
<td></td>
</tr>
<tr class="data">
<td>4th</td>
<td>4.01</td>
<td>4</td>
<td></td>
</tr>
</table>

Categories