so we all know document.getElementsByClassName and document.getElementsByTagName are live HTMLCollections.
I googled and can't seem to find the answer to this, maybe I just don't get it, who can explain it to me?
So I made 2 examples, one with adding a class attribute, the other with bgcolor. Why does the first act like expected and the other gets it's job done...
Why does the TagName one work differently even it's a HTMLCollection in the first example?
How can I know which will work normally and which wont??
https://jsfiddle.net/adkuca/84ryjp7s/2/
https://jsfiddle.net/adkuca/f1o9h7be/
var ran = document.getElementsByClassName('wasd');
/*var ran = document.getElementsByTagName('td');*/
document.getElementById('btn').addEventListener('click', func);
function func() {
console.log(ran); //HTMLCollection, all 6
console.log(ran.length); //6 with both
for (let i = 0; i < ran.length; i++) {
ran[i].setAttribute("class", "green");
}
console.log(ran); //HTMLCollection, all 6 with TagName, every 2nd with ClassName
console.log(ran.length); //6 with TagName, 3 with ClassName
}
tr, td {
border: 1px solid black;
height: 20px;
width: 20px;
}
.green {
background-color: green;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<button id="btn">func</button>
<table>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
</table>
</body>
</html>
var ran = document.getElementsByClassName('wasd');
/*var ran = document.getElementsByTagName('td');*/
document.getElementById('btn').addEventListener('click', func);
function func() {
console.log(ran); //HTMLCollection, all 6
console.log(ran.length); //6 with both
for (let i = 0; i < ran.length; i++) {
ran[i].setAttribute("bgcolor", "green");
}
console.log(ran); //HTMLCollection, all 6
console.log(ran.length); //6 with both
}
tr, td {
border: 1px solid black;
height: 20px;
width: 20px;
}
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<button id="btn">func</button>
<table>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
</table>
</body>
</html>
They both work normally and in the same way. The className appears to work differently because you're effectively removing elements from the list you're working with, while you're going through it.
when you use setAttribute("class", "green"); you're replacing the "wasd" class with "green"
This will work if you add a class instead of replacing the current one using ele.classList.add(class)
https://jsfiddle.net/84ryjp7s/3/
Ok to sum it up for ppl who might have same question.
so if you get a collection with ClassName, means everything will be behaving normally untill you remove the current class you gathered the collection with.
if it was class="a b", you can add any class, but if you delete/change 1 of those it ruins the HTML collection
Same with any other HTMLCollection / live NodeList
if you gather with getElementsByTagName, you can change class but you can't change the td's, if you try to remove the div, you ruined the collection
https://jsfiddle.net/adkuca/c00fqmts/
as it counts you're removing td's, therefore chaning the HTML collection, shrinking it by 1, therefore shrinking the ran.length by 1, so you get half iterations, and you add a new td half less.
examine this: https://jsfiddle.net/adkuca/c7jb0es8/
but if you really want to do gather classes with classname and then change them, you can store them into an array and then change.
Array.from(document.getElementsByClassName('wasd')).forEach(function(itm){
itm.setAttribute('replaced-wasd');
});
var ran = document.getElementsByClassName('wasd');
/*var ran = document.getElementsByTagName('td');*/
document.getElementById('btn').addEventListener('click', func);
function func() {
console.log(ran); //HTMLCollection, all 6
console.log(ran.length); //6 with both
for (let i = 0; i < ran.length; i++) {
console.log(ran.length);
ran[i].setAttribute("class", "green");
console.log(ran.length);
console.log("i = " + i);
console.log(ran);
}
console.log(ran); //HTMLCollection, all 6 with TagName, every 2nd with ClassName
console.log(ran.length); //6 with TagName, 3 with ClassName
}
tr, td {
border: 1px solid black;
height: 20px;
width: 20px;
}
.green {
background-color: green;
}
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<button id="btn">func</button>
<table>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
<tr>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
<td class="wasd"></td>
</tr>
</table>
</body>
</html>
Related
I want to build a page like this, where column B should be editable and whenever the user makes changes in value in column B, Total should be recalculated accordingly.
I want to build a page like this, where column B should be editable and whenever the user makes changes in value in column B, Total should be recalculated accordingly.
I want to build a page like this, where column B should be editable and whenever the user makes changes in value in column B, Total should be recalculated accordingly.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<style>
table, td, th {
border: 1px solid black;
}
table {
border-collapse: collapse;
}
th {
}
</style>
</head>
<body>
<table id="myTable">
<col width="130">
<col width="80">
<tr>
<th>A</th>
<th>B</th>
</tr>
<tr>
<td>Rent</td>
<td class="someClass" contenteditable="true">400</td>
</tr>
<tr>
<td>Food</td>
<td class="someClass" contenteditable="true">200</td>
</tr>
<tr>
<td>Entertainment</td>
<td class="someClass" contenteditable="true">100</td>
</tr>
<tr>
<td>Transportation</td>
<td class="someClass" contenteditable="true">50</td>
</tr>
<tr>
<th>Total</th>
<td class="someTotalClass">200</td>
</tr>
</table>
<script>
function sumOfColumns(){
var totalQuantity = 0;
var totalPrice = 0;
$(".someClass").each(function(){
totalQuantity += parseInt($(this).html());
$(".someTotalClass").html(totalQuantity);
});
$(".classPrice").each(function(){
totalPrice += parseInt($(this).html());
$(".someTotalPrice").html(totalPrice);
});
}
sumOfColumns()
</script>
</body>
</html>
.blur() will bind a handler to function to the blur JavaScript event - you should be fine to just add this beneath your current function in the script tags.
Normally I would say use .change() but that doesn't seem to work with contenteditable divs. If it is possible for you to change to using <input> rather than <div contenteditable="true"> then this could be an alternative for you
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
table,
td,
th {
border: 1px solid black;
}
table {
border-collapse: collapse;
}
th {}
</style>
</head>
<body>
<table id="myTable">
<col width="130">
<col width="80">
<tr>
<th>A</th>
<th>B</th>
</tr>
<tr>
<td>Rent</td>
<td class="someClass" contenteditable="true">400</td>
</tr>
<tr>
<td>Food</td>
<td class="someClass" contenteditable="true">200</td>
</tr>
<tr>
<td>Entertainment</td>
<td class="someClass" contenteditable="true">100</td>
</tr>
<tr>
<td>Transportation</td>
<td class="someClass" contenteditable="true">50</td>
</tr>
<tr>
<th>Total</th>
<td class="someTotalClass">200</td>
</tr>
</table>
<script>
function sumOfColumns() {
var totalQuantity = 0;
var totalPrice = 0;
$(".someClass").each(function() {
totalQuantity += parseInt($(this).html());
$(".someTotalClass").html(totalQuantity);
});
$(".classPrice").each(function() {
totalPrice += parseInt($(this).html());
$(".someTotalPrice").html(totalPrice);
});
}
sumOfColumns();
$('.someClass').blur(function() {
sumOfColumns()
});
</script>
</body>
</html>
Let's say I create a table in HTML which contains a background colour and text. Essentially I want to extract that text from the table using JS in row-major order as long as the text colour doesn't match the background colour.
For example, say this is my table:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Build a table</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="test.js"></script>
<table>
<tbody>
<tr>
<td style="color: #ff00ff; background-color:#FFFFFF">Q</TD>
<td style="background-color: #442244; color: #442244">Y</td>
<td style="color: #FFFF00; background-color:#442244">A</td>
</tr>
<tr>
<td style="color: #FFEEFE; background-color:#990000">Q</td>
<td style="color: #FFFF00; background-color:#FF0">M</td>
<td style="color: #000000; background-color:#FF7777">O</td>
</tr>
</tbody>
</table>
<p id="result"></p>
</body>
I'd get a 3x2 table.
So now I want to get the output to be a concatenated string such as
QAQO since Y and M are invisible
Obviously I need to create a function in JS and I have looked around But i'm not sure what to exactly search when it comes to extracting text from a table and printing it out whilst concatenating
test.js
function getText() {
var arr = $('td').map(function() {
let $td = $(this);
return $td.css('background-color') !== $td.css('color') ? $td.text() : null;}).get();
console.log(arr.join(''));
$('#result').text(arr.join(''));
}
You need to loop through each row and find the td where the background-color is different to the color.
The simplest way to do that would be to use map() to build an array of the values which you can then loop through, or concatenate as needed:
jQuery(function($) {
var arr = $('td').map(function() {
let $td = $(this);
return $td.css('background-color') !== $td.css('color') ? $td.text() : null;
}).get();
console.log(arr.join(''));
$('#result').text(arr.join(''));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td style="color: #ff00ff; background-color: #FFFFFF;">Q</td>
<td style="color: #442244; background-color: #442244;">Y</td>
<td style="color: #FFFF00; background-color: #442244;">A</td>
</tr>
<tr>
<td style="color: #FFEEFE; background-color: #990000;">Q</td>
<td style="color: #FFFF00; background-color: #FF0;">M</td>
<td style="color: #000000; background-color: #FF7777;">O</td>
</tr>
</tbody>
</table>
<p id="result"></p>
Using jQuery:
let concString = "";
$('table tbody').find('tr').each(function(){
$(this).find('td').each(function(){
// condition to get only visible td
if($(this).css('background-color') !== $(this).css('color')){
concString += $(this).text();
}
});
});
console.log(concString);
newbie question here:
I have a huge HTML table, 30 000 rows lets say, each row has an class name (there are cca 10 in total). I need a JS function, that filter (show/hide) all rows with a specific class.
Showing them (removing an attribute) is relatively fast, but hiding them (setting attribute) takes really long.
This is how the table looks like:
<tr class="a" show="off">...</tr>
<tr class="b" show="off">...</tr>
<tr class="c" show="off">...</tr>
<tr class="a" show="off">...</tr>
<tr class="b" show="off">...</tr>
<tr class="c" show="off">...</tr>
there is an CSS rule
tr[show="off"] {
display:none;
}
and my JS code to show them would be removing that show attribute
function showTr (c){
var rows = document.getElementsByClassName(c)
for(var i = 0; i < a.length; ++i) {
rows[i].removeAttribute("show")
}
}
and code to hide them
function hideTr (c){
var rows = document.getElementsByClassName(c)
for(var i = 0; i < a.length; ++i) {
rows[i].setAttribute("show","off")
}
}
I apologize if there is an topic covering this, I have not found anything. And thank you for any advice.
Instead of mutating each DOM node, you could build a css and inject it into <head> and let the browser handle the rest.
const toggleButton = document.querySelector('[data-toggle]');
toggleButton.addEventListener('click', toggleRows);
function toggleRows() {
const STYLE_ID = 'table-row-hide';
const prevStyle = document.getElementById(STYLE_ID);
if (prevStyle) {
prevStyle.parentNode.removeChild(prevStyle);
} else {
const css = `
.hideable {
display: none;
}
`;
const style = document.createElement('style');
style.id = STYLE_ID;
style.innerHTML = css;
document.head.appendChild(style);
}
}
td {
border: 1px solid;
border-collapse: collapse;
padding: 0.25rem;
}
<html>
<head></head>
<body>
<button data-toggle>Toggle</button>
<table>
<tr>
<td>a</td>
<td>b</td>
</tr>
<tr class="hideable">
<td>c</td>
<td>e</td>
</tr>
<tr class="hideable">
<td>f</td>
<td>g</td>
</tr>
<tr>
<td>h</td>
<td>i</td>
</tr>
</table>
</body>
</html>
I'm writing a user-script for a third-party website and looking to select value inside a table which has a preceding TD with a label.
Question: I'm looking to get value1 as the result, but it's selecting the containing TD as well, so I get something else too.
Limitations
Can't modify the HTML to be more query-friendly (duh, it's not my site ;)
The table has no ids (I added them for easier discussion), not even the <table> itself has an id.
The count of the rows is dynamic, so no tr:nth-child.
Tried
I found this question: Selecting an element which has another element as direct child and used the direct selector (tr:has(> td:contains), but it still selects more than needed, because the outer TD also transitively contains label1 and has a sibling.
Notice that the background I set is transparent to show that multiple TDs are selected.
$(function() {
$('#result').text($('tr:has(td:contains("label1")) > td:nth-child(2)').text())
$('tr:has(td:contains("label1"))').css("background", "rgba(255,0,0,0.3)");
});
table { border-collapse: collapse; }
table, th, td { border: 1px solid black; }
td { padding: 4px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<table>
<tr>
<td id="outer">
<table>
<tr><td id="known-info">label1</td><td id="want-to-select">value1</td></tr>
<tr><td>label2</td><td>value2</td></tr>
</table>
</td>
<td id="outer-sibling">something else</td>
</tr>
</table>
<br/>
This should be "value1": "<span id="result"></span>"
You could use :not(:has(td)) in your selector so it should be
$('td:contains("label1"):not(:has(td))').next().text()
This will select td that contains label1 text, but it will ignore parent td because it has another td inside.
var el = $('td:contains("label1"):not(:has(td))').next()
$('#result').text(el.text())
el.css('background', 'blue')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td id="outer">
<table>
<tr>
<td id="known-info">label1</td>
<td id="want-to-select">value1</td>
</tr>
<tr>
<td>label2</td>
<td>value2</td>
</tr>
</table>
</td>
<td id="outer-sibling">something else</td>
</tr>
</table>
<br/> This should be "value1": "<span id="result"></span>"
I want to highlight the current line when mouse moves, is it possible?
It's not table rows, just plain text in paragraphs.
I'm writing a reading helper plugin for Google Chrome, to help browsing within a big chunk of text.
Depends on your definition of "line". If it's a table row or something you can refer to, you can simply do something like this
<table>
<tbody>
<tr>
<td> Item 1</td><td> Item 2</td>
</tr>
<tr>
<td> Item 1</td><td> Item 2</td>
</tr>
</tbody>
</table>
And use this in your stylesheet
table tr:hover td {
background-color: #dddddd;
}
If you want to highlight Table row then apply this
<STYLE>
<!--
tr { background-color: #DDDDDD}
.initial { background-color: #DDDDDD; color:#000000 }
.normal { background-color: #CCCCCC }
.highlight { background-color: #8888FF }
//-->
</style>
<table border="0" cellspacing="0" bgcolor="#CCCCCC" cellpadding="0">
<tr>
<td bgcolor="#FFCC00" WIDTH="100"><b>Brand</b></td>
<td bgcolor="#FFCC00" WIDTH="100"><b>Dimensions</b></td>
<td bgcolor="#FFCC00" WIDTH="100"><b>Price</b></td>
</tr>
<tr style="background-color:#CCCCCC;"
onMouseOver="this.className='highlight'" onMouseOut="this.className='normal'">
<td>Row A</td>
<td>200x300</td>
<td>$200,000.00</td>
</tr>
</table>
If each line is enclosed with in HTML element of there own the and event handler can be attached.
<html>
<script type="text/javascript" src="./jquery-1.4.2.min.js"> </script>
<script type="text/javascript" >
$(document).ready(function() {
$(".lineclass").hover(function() {
$(this).css("backgroundColor","red");
},
function() {
$(this).css("backgroundColor","");
});
});
</script>
<body>
<p class="lineclass">This is line 1</p><br />
<p class="lineclass">This is line 2</p><br />
<p class="lineclass">This is line 3</p><br />
</body>
</html>