Javascript get access to inner table only - javascript

I have a system that generates a list of nested tables. I can't either modify it nor add any id/tags/classes to any parent tables. I also can add neither jQuery nor any other JS library.
I wish to add highlights on mouseover on a row of the inner table (usually I have 2-3 nested tables).
Could someone help me to adjust that sample to my case? The problem with the code that it grabs <td/> tags of parent tables.
var tds = document.getElementsByTagName( "td" );
for( var i = 0; i < tds.length; i++ ) {
tds[i].addEventListener("mouseover", function(){
var children = this.parentNode.getElementsByTagName("td");
for( var j = 0; j < children.length; j++ )
children[j].style.backgroundColor = "green";
});
tds[i].addEventListener("mouseout", function(){
var children = this.parentNode.getElementsByTagName("td");
for( var j = 0; j < children.length; j++ )
children[j].style.backgroundColor = "initial";
});
}
<table>
<tr>
<td>
<table>
<tr>
<td>cell1,1</td>
<td>cell1,2</td>
<td>cell1,3</td>
</tr>
<tr>
<td>cell2,1</td>
<td>cell2,2</td>
<td>cell2,3</td>
</tr>
</table>
</td>
<td> test </td>
</tr>
</table>
Unfortunately, I'm not good enough in JS yet.

I'd ditch the JavaScript and use a simple CSS selector
table table tr:hover {
background: green;
}
<table>
<tr>
<td>
<table>
<tr>
<td>cell1,1</td>
<td>cell1,2</td>
<td>cell1,3</td>
</tr>
<tr>
<td>cell2,1</td>
<td>cell2,2</td>
<td>cell2,3</td>
</tr>
</table>
</td>
<td> test </td>
</tr>
</table>

The answer mentioned above works if the number of nested tables are always 2. According to the requirements, you mentioned that you usually have 2-3 nested tables so it wouldn't work if there are 3 nested tables or more. You would have to change your CSS selectors.
With the solution below, it makes it more dynamic to always get the row of the inner most table as originally requested.
var tables = document.getElementsByTagName("table");
tables[tables.length - 1].classList.add("highlighter");
.highlighter tr:hover {
background: green;
}
<table>
<tr>
<td>
<table>
<tr>
<td>cell1,1</td>
<td>cell1,2</td>
<td>cell1,3</td>
</tr>
<tr>
<td>cell2,1</td>
<td>cell2,2</td>
<td>cell2,3</td>
</tr>
</table>
</td>
<td> test </td>
</tr>
</table>

Related

jQuery highlight text of individual column in table rather than across whole table

I have the following jquery that allows me to highlight all td across all of my html table that exceeds a threshold, in this case 13:
var table = document.getElementById('my_table');
var tbody = table.getElementsByTagName('tbody')[0];
var cells = tbody.getElementsByTagName('td');
var specificheader = tbody.getElementsByTagName('th');
for (var i=0, len=cells.length; i<len; i++){
if (parseInt(cells[i].innerHTML,10) > 13){
cells[i].className = 'red';
}
else if (parseInt(cells[i].innerHTML,10) < -0.1){
cells[i].className = 'green';}
}
With the corresponding HTML:
<table id="my_table">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Vibration 1</th>
<th>Vibration 2</th>
</tr>
</thead>
<tbody>
<tr>
<th>2018-05-14</th>
<td>0.02</td>
<td>0.09</td>
<td>0.11</td>
<td class="red">13.26</td>
<td>1.72</td>
<td class="red">14.98</td>
</tr>
<tr>
<th>2018-05-15</th>
<td>0.02</td>
<td>0.05</td>
<td>0.07</td>
<td class="red">13.27</td>
<td>1.54</td>
<td class="red">14.82</td>
</tr>
</tbody>
</table>
How would I restrict this to highlight only a on specific th, say Vibration 2?
Thank you in advance.
This might sort of a simple way. You can just change your javascript to select the nth-child() of the tr's:
var cells = tbody.querySelectorAll('td:nth-child(7)');
You could probably do something with that to make it dynamic so you can do what you want to programmatically. I think it actually counts the th cells as a child.
Even though a table presents a 2d table, html nodes hierarchy is only one dimensional, so you can't just highlight a column
A possible solution may be premarking all td tags with a class of column number, say something like
<tr>
<td class="col-1">123</td>
<td class="col-2">4.56</td>
...
</tr>
<tr>
<td class="col-1">1234</td>
<td class="col-2">4.567</td>
...
</tr>
Then adding a condition to the jQuery accordingly
A basic implementation:
for (var i=0, len=cells.length; i<len; i++){ if (parseInt(cells[i].innerHTML,10) > 13){
var colcol = cells[i].getAttribute("class");
var tds = document.getElementsByClassName(colcol);
for (var j = 0;j < tds.length ;j++) {
(tds[j]).addClass('red');
}
Notice that if the td has more than one class, we'll need to get just the column class
Which can be done by using split on the colcol var then taking the 1st class
or using regexp etc.

Collapsing and expanding multiple nested rows in jQuery

I need a little help with collapsing and expanding nested rows. Currently my code below expands and collapses as desired at the first level but the subsequent levels also show.
$(document).ready(function(e) {
$('.collapseTitle').click(function() {
$(this).parent()
.parent()
.next('tbody')
.toggleClass('collapsed');
});
});
.collapsed {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td class="collapseTitle">Title</td>
</tr>
</thead>
<tbody class="collapsed">
<tr>
<td>Level 1</td>
</tr>
<tr>
<td>Level 2</td>
</tr>
</tbody>
</table>
I am trying to achieve that Level 1 expands when "collapseTitle" is clicked and that only when "collapseAccount" is clicked, does Level 2 expand. Now I know that my code should look something like the below, but I am struggling...
<table>
<thead>
<tr>
<td class="collapseTitle">Title</td>
</tr>
</thead>
<tbody>
<tr class="collapsed account">
<td class="collapseAccount">Level 1</td>
</tr>
<tr class="collapsed level">
<td>Level 2</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(function(e) {
$('.collapseTitle').click(function() {
$(this).parent().parent().next('tbody tr').toggleClass('account');
});
});
$(document).ready(function(e) {
$('.collapseAccount').click(function() {
$(this).next('tr').toggleClass('level');
});
});
</script>
Any help would be greatly appreciated.
The following code should do it. I hope it helps with what you want to achieve:
collapses/expands columns when clicking on the header/title of the column and
collapses/expands all rows following the account row when clicking on it (until the next account row)
The only thing you need to do is add the class account to the higher level rows. You can do this pretty easily when you're displaying these with a loop.
.collapsed {
/* using visibility, since display causes layout issues */
/* due to empty rows rows/columns collapsing */
visibility: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td>Title1</td>
<td>Title2</td>
</tr>
</thead>
<tbody>
<tr class="account">
<td class="collapsed">Account Summary - Account A</td>
<td class="collapsed">Account Summary - Account A</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part I - Account A</td>
<td class="collapsed">Account Details Part I - Account A</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part II - Account A</td>
<td class="collapsed">Account Details Part II - Account A</td>
</tr>
<tr class="account">
<td class="collapsed">Account Summary - Account B</td>
<td class="collapsed">Account Summary - Account B</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part I - Account B</td>
<td class="collapsed">Account Details Part I - Account B</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(() => {
/* the following handlers expand/collapse the columns */
$('thead > tr > td').each((i, el) => {
$(el).click(() => {
const colIndex = $(el).index() + 1;
const nRows = $('tbody > tr').length;
for (let j = 0; j < nRows; j += 1) {
let cellSelector = `tbody > tr:nth-child(${j+1})`
cellSelector += `> td:nth-child(${colIndex})`;
$(cellSelector).toggleClass('collapsed');
}
})
})
/* the following handlers expand/collapse the account-details rows */
$('tbody > tr.account').each((i, el) => {
$(el).click(() => {
$(el).nextUntil('.account').each((j, ele) => {
$(ele).toggleClass('collapsed');
})
})
})
});
</script>
Your jQuery selectors are just a bit off for the toggleClass. You can use the class names of the row to toggle. Also you should create a class to be toggled that displays the row/hides it. For example:
edit:
I now created the titles and rows dynamically to give you a better idea of how this can be done using data- attributes.
You will have a title td and a row td that match on a data- attribute, so when you click a title and corresponding tr will be shown. So for example if you click title 1 (with a data-index=1) then the tr with the attribute data-rowindex=1 will be shown.
$(document).ready(function(e) {
createTable();
$('.collapseTitle').click(function() {
// grab the data-index value from the clicked title
let index = $(this).attr("data-index");
// find a tr that has the attribute data-rowindex and it matches index
$("tr[data-rowindex='" + index + "']").toggleClass("collapsed");
});
});
function createTable(){
// create the titles and the level rows
for(let i = 0; i < 3; i++){
// create the title row
let $trTitle = $('<tr>');
let $tdTitle = $('<td>', {class: "collapseTitle", text: "Title " + i});
$tdTitle.attr("data-index", i);
let $finalTitleRow = $trTitle.append( $tdTitle );
// create the level row
let $trLevel = $('<tr>', {class: "collapsed account"} );
$trLevel.attr("data-rowindex", i);
let $tdLevel = $('<td>', {text: "Level " + i});
let $finalLevelRow = $trLevel.append( $tdLevel );
// add the title and level row pairs to the head and body
$("#myTableHead").append($finalTitleRow[0]);
$("#myTableBody").append($finalLevelRow[0]);
}
}
.collapsed {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead id="myTableHead">
</thead>
<tbody id="myTableBody">
</tbody>
</table>
I managed to find the answer I was looking for... Thank you to "stackoverfloweth",
Answer To My Question
The snippet of code which has helped me thus far is below,
$('.parent-row').click(function(){
var $element = $(this).next();
while(!$element.hasClass('parent-row')){
$element.toggle();
if($element.next().length >0){
$element = $element.next();
}
else{
return;
}
} });
$('.child-row.has-children').click(function(){
var $element = $(this).next();
while($element.hasClass('child-child-row')){
$element.toggle();
if($element.next().length >0){
$element = $element.next();
}
else{
return;
}
} });

Using getAttribute to change a cell's background color

I'm attempting to loop through the cells of a table using getAttribute for a cell with a blue background, then changing it to a yellow background. I know CSS can easily accomplish this task, however I want to understand using JavaScript.
Here is my code:
<table>
<tr>
<td>
Cell 1
</td>
<td>
Cell 2
</td>
</tr>
<tr>
<td>
Cell 3
</td>
<td style="background-color:blue">
Cell 4
</td>
</tr>
</table>
var cells = document.getElementsByTagName('td');
for(i=0; i < cells.length; i++) {
if(cells[i].getAttribute('backgroundColor') == true) {
this.style.backgroundColor = "yellow";
}
}
Console log isn't returning any errors. Any thoughts guys?
Thank you!
Note that background property isn't a DOM attribute, it's a style attribute.
Note: If you refer to the specified td element, use cells[i] instead, because this keyword in this particular case will not refer to the actually iterated element, but to the window object.
var cells = document.getElementsByTagName('td');
for (i = 0; i < cells.length; i++) {
if (cells[i].style.background == 'blue') {
cells[i].style.background = "yellow";
}
}
<table>
<tr>
<td>
Cell 1
</td>
<td>
Cell 2
</td>
</tr>
<tr>
<td>
Cell 3
</td>
<td style="background:blue">
Cell 4
</td>
</tr>
</table>
In case that you would like to refer to the DOM attribute, you could apply following code:
if (cells[i].getAttribute('style') == 'background:blue') {
cells[i].style.background = "yellow";
}

background color using html n css

I'm trying to loop through a table to get each TD value. If the value is below a specific number then I'll do something.
</head>
<body>
<table id="tableData" name="tableData">
<tr>
<td>abc</td>
<td>5</td>
<td>abcd</td>
</tr>
<tr>
<td>aaaa</td>
<td>15</td>
<td>bbbb</td>
</tr>
<tr>
<td>ccc</td>
<td>25</td>
<td>dddd</td>
</tr>
</table>
</body>
above is my code .. i need to change the background colors of the 2nd column as below . if the value of the 2nd column element is <= 10 then the color is green , from 11-20 its yellow and above 21 its red.
I have given the sample code here. actually in real , the table is derived from the database , iy may have any nomber of rows. so i need to color the column as the page gets loaded.
Any help is appreciated, thanks.
The following modified plain JavaScript will colour the <td> elements as required:
function checkForm() {
var tds = document.querySelectorAll('td[id]');
for (var j = 0; j < tds.length; j++) {
var i = tds[j].innerHTML;
if(i < 10){
tds[j].style.backgroundColor = 'green';
} else if(i >= 11 && i <= 20){
tds[j].style.backgroundColor = 'yellow';
} else if(i > 20){
tds[j].style.backgroundColor = 'red';
}
}
}
but you will need to modify the HTML to give the <td>s unique ID values, for example
<body onload="checkForm();">
<table id="tableData" name="tableData">
<tr>
<td>abc</td>
<td id="a">5</td>
<td>abcd</td>
</tr>
<tr>
<td>aaaa</td>
<td id="b">15</td>
<td>bbbb</td>
</tr>
<tr>
<td>ccc</td>
<td id="c">25</td>
<td>dddd</td>
</tr>
</table>
</body>
If it is always the middle cell that needs colour you could remove the ids completely and rely on the fact that is is "always the middle cell". For example use the following selector instead:
var tds = document.querySelectorAll('td:nth-child(2)');
The only limitation is that querySelectorAll is that it is not supported by IE<9. All other browsers support it.
Since the cell that requires a background-color is always the 2nd cell, you can use the CSS nth-child selector as the argument to in querySelectorAll() to "select the 2nd <td> child element of the parent", which in this case is the <tr>.
So td:nth-child(2) finds the the <td>two</td> element for the following HTML:
<tr>
<td>one</td>
<td>two</td>
<td>three</td>
</tr>
See some examples of how :nth-child works.
Demo of id-less solution (for if the cell to colour is always the middle one).
Since OP is stuck with IE8 and IE8 does not support :nth-child an alternative adjacent sibling combinator can be used to target the 2nd child with the caveats that there must only be 3 <td> and the 3rd must not contain any numbers.
Update:
Based on the actual requirements of needing to work in IE8 and add background-color to the 6th column, here is a simpler (to read) and more cross-browser compatible jQuery solution:
jsBin demo (so it works on IE8)
HTML
Remove the onload="checkForm(); from <body>
<table id="tableData" name="tableData">
<tr>
<td></td><td></td><td></td><td></td>
<td>abc</td>
<td>5</td>
<td>abcd</td>
</tr>
<tr>
<td></td><td></td><td></td><td></td>
<td>aaaa</td>
<td>15</td>
<td>bbbb</td>
</tr>
<tr>
<td></td><td></td><td></td><td></td>
<td>ccc</td>
<td>25</td>
<td>dddd</td>
</tr>
</table>
JavaScript
$(function(){
var tds = $('td:nth-child(6)');
for (var j = 0; j < tds.length; j++) {
var i = tds[j].innerHTML;
if(i < 10){
tds[j].style.backgroundColor = 'green';
} else if(i >= 11 && i <= 20){
tds[j].style.backgroundColor = 'yellow';
} else if(i > 20){
tds[j].style.backgroundColor = 'red';
}
}
});
First off, don't use the same ID's for any elements on a page. It is a unique identifier. If you want to reference more than one element, then use a class instead.
The simplest way to achieve what you want is using two classes - one to define xxx, and then one to define its status (colour). Also, if you use semantic naming (instead of .green,.yellow,.red) you will get good understanding of your code.
ex
.xxx{ font-weight: bold;}
.less10 { background: green;}
.between1120 {background: yellow; }
.over21 { background: red; }
You cannot set CSS depending on the content inside the element. For this you would need some simple jQuery/javascript or your chosen programming language to loop through all the xxx-classes in the table, and add the status class accordingly.
ex
<td class="xxx less10">5</td>
<td class="xxx between1120">15</td>
<td class="xxx over21">35</td>
Firstly you should change the ID xxx to Class xxx.
function checkForm(){
$('td.xxx').each(function(){
var val=parseInt($(this).text());
if(val<=10) $(this).css({background:'green'});
else if(val>10 && val<=20) $(this).css({background:'yellow'});
else if(val>20) $(this).css({background:'red'});
}
}
I think that should work with jQuery.
Here is what you want :
Demo Here</>
<table id="tableData" name="tableData">
<tr>
<td>
abc
</td>
<td class="xxx">
5
</td>
<td>
abcd
</td>
</tr>
<tr>
<td>
aaaa
</td>
<td class="xxx">
15
</td>
<td>
bbbb
</td>
</tr>
<tr>
<td>
ccc
</td>
<td class="xxx">
25
</td>
<td>
dddd
</td>
</tr>
</table>
Javascript
$(document).ready(function () {
var arr = $(".xxx").toArray();
for (var i = 0; i < arr.length; i++) {
if (parseInt(arr[i].innerText) < 10) {
$(arr[i])[0].bgColor = "green";
}
else if (parseInt(arr[i].innerText) >= 11 && parseInt(arr[i].innerText) <= 20) {
$(arr[i])[0].bgColor = 'yellow';
}
else if (parseInt(arr[i].innerText) > 20) {
$(arr[i])[0].bgColor = 'red';
}
}
});

HTML and JavaScript auto increment number

I am new to HTML and JavaScript. I got a problem like this in HTML (This code below only visualize the problem for you to easy to reference.)
<tr>
<td>1</td>
<td>Harry</td>
</tr>
<tr>
<td>2</td>
<td>Simon</td>
</tr>
<td>3</td>
<td>Maria</td>
</tr>
</tr>
<td>4</td>
<td>Victory</td>
</tr>
This is a name list, however the problem is that sometime i need to add more name into this table and I HAVE TO ADD in front of Number 1, so meaning i have to re-write the number list, (EX: 1 1 2 3 4 --> 1 2 3 4 5). I feel that is not a good way.
NOTE: I don't want to change the list number decrease from top to bottom. And this is a HTML file so can't apply PHP
Anyone can help me to make the number to a variable like "i" and a function can help me to fill variable i increment from top to bottom automatically like
<tr>
<td>i</td>
<td>Harry</td>
</tr>
<tr>
<td>i</td>
<td>Simon</td>
</tr>
<td>i</td>
<td>Maria</td>
</tr>
</tr>
<td>i</td>
<td>Victory</td>
</tr>
Function Fill_i for example:
I think that JavaScript should be used in this case. Thanks for your help and suggestion on this problem.
Again: I am not allowed to use PHP or ASP and when I add a new name, I add it manually by HTML.
You can use a css counter - MDN
table {
counter-reset: section;
}
.count:before {
counter-increment: section;
content: counter(section);
}
<table>
<tr>
<td class="count"></td>
<td>Harry</td>
</tr>
<tr>
<td class="count"></td>
<td>Simon</td>
</tr>
<tr>
<td class="count"></td>
<td>Maria</td>
</tr>
<tr>
<td class="count"></td>
<td>Victory</td>
</tr>
</table>
FIDDLE
This should work for you:
<table>
<tr>
<td>Harry</td>
</tr>
<tr>
<td>Simon</td>
</tr>
<tr>
<td>Maria</td>
</tr>
<tr>
<td>Victory</td>
</tr>
</table>
<script>
var tables = document.getElementsByTagName('table');
var table = tables[tables.length - 1];
var rows = table.rows;
for(var i = 0, td; i < rows.length; i++){
td = document.createElement('td');
td.appendChild(document.createTextNode(i + 1));
rows[i].insertBefore(td, rows[i].firstChild);
}
</script>
The script should be placed immediately after your table. It goes through each row of your table and adds an extra cell to the beginning with the incrementing number inside that cell.
JSFiddle Demo
Edit: seems like the other solution posted would work do (was added while I typed this up).
You really should be using PHP to do something dynamic like this, which would become trivial with a single for loop.
However, if you insist on using HTML/Javascript (or perhaps this is a 'static page'...) then what you are asking should be possible.
You could add a class to each of the <td> elements you want to use, so:
<tr>
<td class='personid'>i</td>
<td>Harry</td>
</tr>
<tr>
<td class='personid'>i</td>
<td>Simon</td>
</tr>
<td class='personid'>i</td>
<td>Maria</td>
</tr>
</tr>
<td class='personid'>i</td>
<td>Victory</td>
</tr>
Then you would have a javascript function that does something like this:
var list = document.getElementsByClassName("personid");
for (var i = 1; i <= list.length; i++) {
list[i].innerHTML = i;
}
Are you sure you don't want an ordered list?
<ol>
<li>Fred</li>
<li>Barry</li>
</ol>
<script>
function addRow(index, name){
var tbody = document.getElementById("nameList");
var row = document.createElement("tr");
var data1 = document.createElement("td");
data1.appendChild(document.createTextNode(index));
var data2 = document.createElement("td");
data2.appendChild(document.createTextNode(name));
row.appendChild(data1);
row.appendChild(data2);
tbody.appendChild(row);
}
var name=new Array();
name[0]="Harry";
name[1]="Simon";
name[2]="Maria";
name[3]="Victory";
for(var i=0; i < name.length; i++) {
addRow(i,name[i]);
}
</script>
<html>
<body>
<table id="nameList">
</table>
</body>
</html>
I would say do this (im going to assume you are not going to load in jquery or anything fancy):
<html>
<head>
<script type="text/javascript>
function writeTable(){
// list of names
var myList = [ "name1", "name2", "etc", "etc"];
// your variable to write your output
var outputTable = "<table>";
//the div to write the output to
var outputDiv = document.getElementById("output");
//the loop that writes the table
for (var i=0; i<myList.length; i++){
outputTable += "</tr><td>"+i+"</td><td>"+myList[i]+"</td></tr>";
}
//close the table
outputTable += "</table>";
//write the table
outputDiv.innerHTML = outputTable;
}
</script>
</head>
<body onload=writeTable()>
<div id='output'></div>
</body>
</html>
hope this helps :)
Try this
$(document).ready(function() {
var addSerialNumber = function () {
$('table tr').each(function(index) {
$(this).find('td:nth-child(1)').html(index);
});
};
addSerialNumber();
});

Categories

Resources