CSS wildcard selection - javascript

I use this wildcard in css to select the data containing "," commas.
td[data-content*=","]{
background-color: yellow;
}
Is there a way to make a distinction for the numbers of "," in the data. I can highlight data containing one comma in yellow. I'd like to highlight data containing two commas in green. Is there a way to do this with CSS? Thanks.
I want to use different colors at the same time according to the number of commas data contains. So the data like (1,2) will be yellow. and the data like (1,2,3) will be green.

Here's a jQuery solution:
$('td').each(function() {
var c = $(this).text();
if (!c) return;
var commas = c.split(",").length - 1;
if (commas === 1) $(this).css("background-color", "yellow");
if (commas === 2) $(this).css("background-color", "green");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>a</td>
<td>a,b</td>
<td>a,b,c</td>
</tr>
</tbody>
</table>
Should be pretty self-explanatory:
grab tds
read data-content attribute and count commas
set style

You cannot do this in pure CSS.
The CSS attribute selectors only allow literal matching and no wildcard/glob/regexp matching
See here for a definition: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
I have made a VanillaJS solution. In that I count the comma matches in the data-content attribute and add a new data-content-classification attribute with different values depending on number of matches.
console.clear()
// Start after loading of the document
window.addEventListener('load', function() {
// get all the table cells with data-content attribute
var tdContents = document.querySelectorAll('td[data-content]');
// loop over those cells
for (var i = 0; i < tdContents.length; i++) {
// anonymous function which gets a single table cell element as argument
;(function(el) {
// get the attribute's value
var dc = el.getAttribute('data-content')
// react according to the length of the comma matches (with fallback to prevent error)
switch ((dc.match(/,/g) || []).length) {
case 0:
// if no comma found
el.setAttribute('data-content-classification', 0);
break;
case 1:
// if one comma found
el.setAttribute('data-content-classification', 1);
break;
default:
// default, meaning more than one comma
el.setAttribute('data-content-classification', 2);
}
})(tdContents[i]);
}
})
#charset "UTF-8";
td[data-content-classification="1"] {
background-color: yellow;
}
td[data-content-classification="2"] {
background-color: red;
}
td:after,
td:before {
order: -2;
content: "data-content: " attr(data-content);
background-color: goldenrod;
min-width: 50px;
display: inline-block;
margin: 2px;
padding: 2px;
margin-right: 10px;
}
td:after {
order: -1;
content: "data-content-classifiction: " attr(data-content-classification) " ";
}
td {
padding: 3px;
display: flex;
width: 100%;
}
<table>
<tr>
<td>Lorem, ipsum dolor.</td>
</tr>
<tr>
<td data-content="1">Lorem, ipsum dolor.</td>
</tr>
<tr>
<td data-content="1,2">Lorem, ipsum dolor.</td>
</tr>
<tr>
<td data-content="2,3">Eveniet, sunt reiciendis.</td>
</tr>
<tr>
<td data-content="1,2,3">Accusantium, quam impedit.</td>
</tr>
<tr>
<td data-content="1,2,3,5">Accusantium, quam impedit.</td>
</tr>
</table>

Note that this answer contains jQuery notation, and so it will require a jQuery library to work.
What you could do is loop through all your data-content that has a , like you initially wanted with your wildcard selector.
You can then use $(this).attr() to get the contents of your custom attribute.
You can then take that string, turn it into an array using .split(). After that you count the length of the array. Remember to subtract by 1, because arrays count from 0.
You then check for the condition of commas and set your CSS logic by using the css() function.
Example:
function testing() {
$('[data-content*=","]').each(function() {
var myAttr=$(this).attr('data-content');
var myArr=myAttr.split(",");
var countCommas=myArr.length - 1;
var yellow=1;
var green=2;
if(countCommas == yellow) {
$(this).css("background-color", "yellow");
}
else if(countCommas == green) {
$(this).css("background-color", "green");
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td data-content="1,2">
1,2
</td>
</tr>
<tr>
<td data-content="1,2,3">
1,2,3
</td>
</tr>
<tr>
<td>
No color
</td>
</tr>
</table>
<br />
<button onclick="testing();">Test</button>
You don't need to trigger the function via a button click, I just added that for test purposes, so that you could see the effect.
If you want it to run automatically, all you have to do is put it inside a document.ready block.
Example:
$(document).ready(function() {
$('[data-content*=","]').each(function() {
var myAttr=$(this).attr('data-content');
var myArr=myAttr.split(",");
var countCommas=myArr.length - 1;
var yellow=1;
var green=2;
if(countCommas == yellow) {
$(this).css("background-color", "yellow");
}
else if(countCommas == green) {
$(this).css("background-color", "green");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td data-content="1,2">
1,2
</td>
</tr>
<tr>
<td data-content="1,2,3">
1,2,3
</td>
</tr>
<tr>
<td>
No color
</td>
</tr>
</table>

Related

Move HTML Table Cell up or down (not row)

I am working on a project where I have an HTML table and I need to offer users the option to swap two HTML table cells content.
Specifically, a user can click to select a row, then choose to move that row up or down. Really, they are only moving the content of column 2, which represents the information. Column 1 represents order, which will not change.
The table will be two total columns.
Column 1 will represent linear order (i.e. 1-10), it will not change.
Column 2 will be database-provided information (in the example code I provided last name).
I have built two buttons, up and down, and utilized two Javascript functions that allow a user to select a row and move it up or down.
The current code successfully moves a whole row to go up or down, but I only need the cell contents of column 2 to go up or down.
Please take a look at the provided code and JSFiddle and let me know how I can solve this? Thanks in advance!
var index; // variable to set the selected row index
function getSelectedRow() {
var table = document.getElementById("table");
for (var i = 1; i < table.rows.length; i++) {
table.rows[i].onclick = function() {
// clear the selected from the previous selected row
// the first time index is undefined
if (typeof index !== "undefined") {
table.rows[index].classList.toggle("selected");
}
index = this.rowIndex;
this.classList.toggle("selected");
};
}
}
getSelectedRow();
function upNdown(direction) {
var rows = document.getElementById("table").rows,
parent = rows[index].parentNode;
if (direction === "up") {
if (index > 1) {
parent.insertBefore(rows[index], rows[index - 1]);
// when the rowgo up the index will be equal to index - 1
index--;
}
}
if (direction === "down") {
if (index < rows.length - 1) {
parent.insertBefore(rows[index + 1], rows[index]);
// when the row go down the index will be equal to index + 1
index++;
}
}
}
tr {
cursor: pointer
}
.selected {
background-color: red;
color: #fff;
font-weight: bold
}
button {
margin-top: 10px;
background-color: #eee;
border: 2px solid #00F;
color: #17bb1c;
font-weight: bold;
font-size: 25px;
cursor: pointer
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
<meta content="30" http-equiv="refresh">
<title> {{.Title}} </title>
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
#media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
</head>
<body>
<header>
</header>
<main>
<table id="table" border="1">
<tr>
<th>Order</th>
<th>Last Name</th>
</tr>
<tr>
<td>1</td>
<td>Smith</td>
</tr>
<tr>
<td>2</td>
<td>Johnson</td>
</tr>
<tr>
<td>3</td>
<td>Roberts</td>
</tr>
<tr>
<td>4</td>
<td>Davis</td>
</tr>
<tr>
<td>5</td>
<td>Doe</td>
</tr>
</table>
<button onclick="upNdown('up');">&ShortUpArrow;</button>
<button onclick="upNdown('down');">&ShortDownArrow;</button>
</main>
<!-- Bootstrap core JavaScript -->
<script src="/vendor/jquery/jquery.min.js"></script>
<script src="/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="/js/sidebar.js"></script>
</body>
</html>
Link to JSFiddle
This answer makes changes the posted code for simplicity (at least on the surface) and to prevent moving the header row down the table using the buttons:
A reference to the selected row is held rather than an index.
In HTML, the header row has been placed within a thead element, and the data rows within a tbody element (important in code).
When moving a row, the order of two rows is reversed, and then the textContent of their first cells swapped - without moving the "order" column cells to different rows. If this is too simple you could swap the innerHTML property of the cells instead.
Whilst making changes, clicking a row a second time was used to deselect it: clicking outside the table would be another thing you could monitor, as you wish.
"use strict";
const tbody = document.querySelector("#table tbody");
let selected = null;
tbody.addEventListener("click", function(e){
let row = e.target.closest("tr");
if( row === selected) {
row.classList.toggle("selected")
selected = null;
}
else {
if(selected) {
selected.classList.toggle("selected");
}
selected = row;
row.classList.toggle("selected");
}
});
function upNdown( direction) {
let up, down;
if( selected) {
up = direction == "up" ? selected : selected.nextElementSibling;
down = direction == "up" ? selected.previousElementSibling : selected;
if( up && down) {
tbody.insertBefore(up, down); // put up before down
var temp = up.firstElementChild.textContent; // swap first cells' text content
up.firstElementChild.textContent = down.firstElementChild.textContent;
down.firstElementChild.textContent = temp;
}
}
}
tr {
cursor: pointer
}
.selected {
background-color: red;
color: #fff;
font-weight: bold
}
<table id="table" border="1">
<thead>
<tr>
<th>Order</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Smith</td>
</tr>
<tr>
<td>2</td>
<td>Johnson</td>
</tr>
<tr>
<td>3</td>
<td>Roberts</td>
</tr>
<tr>
<td>4</td>
<td>Davis</td>
</tr>
<tr>
<td>5</td>
<td>Doe</td>
</tr>
</tbody>
</table>
<button onclick="upNdown('up');">&ShortUpArrow;</button>
<button onclick="upNdown('down');">&ShortDownArrow;</button>
It depends on exactly what you want. You mention having tried moving innerHTML so this snippet does that - leaving any attributes on the two tds unmoved (see Note below):
var index; // variable to set the selected row index
function getSelectedRow() {
var table = document.getElementById("table");
for (var i = 1; i < table.rows.length; i++) {
table.rows[i].onclick = function() {
// clear the selected from the previous selected row
// the first time index is undefined
if (typeof index !== "undefined") {
table.rows[index].classList.toggle("selected");
}
index = this.rowIndex;
this.classList.toggle("selected");
};
}
}
getSelectedRow();
function upNdown(direction) {
var rows = document.getElementById("table").rows,
parent = rows[index].parentNode;
if (direction === "up") {
if (index > 1) {
// get the relevant cell which is the second one as we know only tds are the children
let td = rows[index].children[1];
let tdAbove = rows[index - 1].children[1];
let temp = td.innerHTML;
td.innerHTML = tdAbove.innerHTML;
tdAbove.innerHTML = temp;
// when the rowgo up the index will be equal to index - 1
index--;
}
}
if (direction === "down") {
if (index < rows.length - 1) {
let td = rows[index].children[1];
let tdBelow = rows[index + 1].children[1];
let temp = td.innerHTML;
td.innerHTML = tdBelow.innerHTML;
tdBelow.innerHTML = temp;
// when the row go down the index will be equal to index + 1
index++;
}
}
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
#media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
tr {
cursor: pointer
}
.selected {
background-color: red;
color: #fff;
font-weight: bold
}
button {
margin-top: 10px;
background-color: #eee;
border: 2px solid #00F;
color: #17bb1c;
font-weight: bold;
font-size: 25px;
cursor: pointer
}
<body>
<header>
</header>
<main>
<table id="table" border="1">
<tr>
<th>Order</th>
<th>Last Name</th>
</tr>
<tr>
<td>1</td>
<td>Smith</td>
</tr>
<tr>
<td>2</td>
<td>Johnson</td>
</tr>
<tr>
<td>3</td>
<td>Roberts</td>
</tr>
<tr>
<td>4</td>
<td>Davis</td>
</tr>
<tr>
<td>5</td>
<td>Doe</td>
</tr>
</table>
<button onclick="upNdown('up');">&ShortUpArrow;</button>
<button onclick="upNdown('down');">&ShortDownArrow;</button>
</main>
Note: in the question the idea of moving a whole element, not just its contents, is introduced. You could do that instead of swapping the contents (i.e. all the attributes would also get moved) by using for example outerHTML. However, this may not be what you want because there may be for example an inline style on the top element which highlights it in gold if this is a leader board. It depends on exactly what your requirement is.
Note also that the snippet assumes the table is well-formed in the sense that there are no non-td elements as direct children within the selectable rows.

Filtering with different price ranges and one attribute

I'm looking for a working example or fiddle that has filtering for price ranges along with some properties (such as 'On Sale'). Basically, I would like to filter an item to it's price range and to also see products that are on sale too in that price range. I have the price ranges working but how do I implement multiple ranges when the multiple checkboxes are checked. Also, how can I implement filtering the sale attribute?
Any help is appreciated.
The structure of the HTML and assignment of data-* attributes are sloppy and cluttered. Using a ton of divs makes the code difficult to ascertain purpose (if any).
Attributes such as [data-date] is not necessary in regards to the question (and probably not necessary in the real code either). Although functioning, attributes [min] and [max] are not standard on checkboxes, use [data-min] and [data-max] and make sure when using any attribute with a number value be converted into a true number.
The usefulness concerning something on sale and within a selected price range is dubious since the sale item is in a price range regardless. The sale items should simply be shown if a .sale class is assigned. Details are commented in demo.
// Clicking summary calls toggleFilters()
$('summary').on('click', toggleFilters);
/*
Any changes to form.filter calls filterItems()
The second parameter (event.data) indicates what is considered $(this)
*/
$('.filter').on('change', ':checkbox', filterItems);
// If details is closed, the table cells are shown and the .filter is reset
function toggleFilters(e) {
if (!!$(this).parent('details').attr('open')) {
$('tbody td').show();
$('.filter')[0].reset();
}
}
/*
//A Hide all cells in tbody
//B On each checkbox...
if it is checked and has class .priceRange...
...get its [data-min] and [data-max] into an array and add that to the ranges array
//C if it is checked and has class .saleItems sales flag is true
*/
function filterItems(e) {
let ranges = [];
let sales = false;
$('tbody td').hide(); //A
$(':checkbox').each(function() {
if (this.checked) {
if ($(this).is('.priceRange')) { //B
let min = Number($(this).data('min'));
let max = Number($(this).data('max'));
ranges.push([min, max]);
}
if ($(this).is('.saleItems')) { //C
sales = true;
}
}
});
/*
//A On each [data-price] cell...
//B Collect all [data-item] cells into an array
//C Collect all .img cells into an array
//D if [data-price] has .sale class use the [data-sale] value
//E for each sub array in the ranges array...
//F Run between() first param is price, second param is min of sub array third param
is max of sub array
//G if true then show cells [data-price], [data-item], and .img cells associated with
current index of the arrays images and items
//H if sales flag is true and current checkbox is checked and has the .saleItems class...
do the same as line G
*/
$('.products').find('[data-price]').each(function(index) {
const items = $('[data-item]').toArray();
const images = $('.img').toArray();
let price = this.matches('.sale') ?
Number($(this).data('sale')) : Number($(this).data('price'))
for (let range of ranges) {
if (between(price, range[0], range[1])) {
$(this).show();
$(images[index]).show();
$(items[index]).show();
}
}
if (sales && $(this).is('.sale')) {
$(this).show();
$(images[index]).show();
$(items[index]).show();
}
});
}
/*
Utility function that determines if a given number is in a given range
*/
function between(num, min, max) {
return num >= min && num <= max;
}
/*
Utility function that will set the images of .img cells with an array of urls
*/
function setImages(array) {
$('.img').each(function(index) {
$(this).css('background-image', `url(${array[index]})`);
});
}
/* Utility function that sets colspan values according to max number of cells in a row
*/
function tableStructure() {
let cs = [];
$('tr').each(function() {
let size = $(this).children().length;
cs.push(size);
});
let sorted = cs.sort();
$('.cs').attr('colspan', sorted[sorted.length - 1]);
$('tbody').find('tr').last().prev('tr').find('td').css('border-bottom', '0');
}
const images = ['https://www.dhresource.com/webp/m/0x0s/f2-albu-g6-M00-F1-0F-rBVaSFqzohOAJ_2FAAFgtbG9J2U328.jpg/women-new-large-size-casual-tops-loose-ladies.jpg', 'https://www.sherainbow.com/1634-large_default/pogt-casual-long-sleeve-t-shirt-women-loose-fit-wifey-print-slouchy-shirt-top-pink-cb12e6qb3bp.jpg', 'https://sc02.alicdn.com/kf/HTB1ZlLYbHsTMeJjy1zeq6AOCVXar/New-Fashion-Design-Women-plain-black-t.jpg', 'https://aritzia.scene7.com/is/image/Aritzia/large/s19_07_a06_63877_16624_on_a.jpg', 'https://cdn.forcast.com.au/media/catalog/product/cache/image/e9c3970ab036de70892d86c6d221abfe/1/8/18p928blk_18t946sto_frontfull_117_cm_2_7.jpg', 'https://image.skechers.com/img/productimages/xlarge/52675_NVOR.jpg', 'https://static.enko-running-shoes.com/2019/img/v5/chaussure-running-enko.jpg'];
tableStructure();
setImages(images);
.products {
table-layout: fixed;
}
caption,
th {
text-align: left;
font-size: 1.15rem;
}
caption {
font-size: 1.5rem;
font-weight: 700
}
td {
border-bottom: 3px ridge grey;
}
tbody td {
padding-bottom: 5px
}
.dept tr:first-of-type>th::before {
content: attr(data-dept);
font-size: 1.25rem
}
.category th::before {
content: attr(data-cat)
}
.item>td::before {
content: attr(data-item);
font-size: 1.2rem
}
.price>td::before {
content: '$'attr(data-price)
}
.price>td::after {
content: '\a0'
}
.price>td.sale::before {
content: '$'attr(data-price);
text-decoration: line-through red
}
.price>td.sale::after {
content: '$'attr(data-sale);
color: green
}
.img {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
min-width: 100px;
min-height: 100px;
}
label {
display: inline-block;
width: 150px;
margin: 0 5px;
border-bottom: 1px solid black;
}
details {
cursor: pointer
}
tbody tr:last-of-type td {
border-bottom: 0;
}
summary {
font-size: 1.25rem;
border-top: 3px ridge grey
}
<table class="products">
<caption>Shop</caption>
<tbody class='dept'>
<tr>
<th class='cs' data-dept='Apparel'></th>
</tr>
<tr class='category'>
<th class='cs' data-cat='Shirts'></th>
</tr>
<tr class='item'>
<td data-item='item 1'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 2'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 3'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td data-price='9.99'><br></td>
<td data-price='23.99'><br></td>
<td class='sale' data-price='32.99' data-sale='17.99'><br></td>
</tr>
<tr class='category'>
<th class='cs' data-cat='Pants'></th>
</tr>
<tr class='item'>
<td data-item='item 4'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 5'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td class='sale' data-price='39.99' data-sale='12.99'><br></td>
<td data-price='75.99'><br></td>
</tr>
<tr class='category'>
<th class='cs' data-cat='Shoes'></th>
</tr>
<tr class='item'>
<td data-item='item 6'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 7'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td data-price='39.99'><br></td>
<td class='sale' data-price='125.99' data-sale='77.99'><br></td>
</tr>
</tbody>
<tfoot>
<tr>
<td class='cs'>
<form class='filter'>
<details>
<summary>Filters</summary>
<label><input class="priceRange" data-min='0' data-max='9.99' type="checkbox" value='true'>Under $10</label>
<label><input class="priceRange" data-min='10' data-max='19.99' type="checkbox">$10 to $20</label>
<label><input class="priceRange" data-min='20' data-max='29.99' type="checkbox">$20 to $30</label>
<label><input class="priceRange" data-min='30' data-max='39.99' type="checkbox">$30 to $40</label>
<label><input class="priceRange" data-min='40' data-max='999' type="checkbox">Over $40</label>
<label><input class="saleItems" type="checkbox" value='true'>On Sale</label>
</details>
</form>
</td>
</tr>
</tfoot>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I'm not really sure what the desired behavior of the sale filter is, but this should put you in the right direction:
updated plunkr
$('.priceFilter').on('change', (e) => {
var filters = $('.priceRange:checked')
.toArray()
.map(el => ({
min: $(el).attr('min'),
max: $(el).attr('max'),
sale: $(el).attr('data-sale')
}));
if (!filters.length) {
$('.item').show();
} else {
$('.item').hide();
var sale = filters.some(el => el.sale == 'True') ? 'True' : 'False';
filters
.forEach(elm => $('.item')
.filter((i, el) =>
parseFloat($(el).attr('data-price')) >= elm.min &&
parseFloat($(el).attr('data-price')) <= elm.max &&
$(el).attr('data-sale') == sale)
.show());
}
});

How to change class for all elements retrieved by document.getElementsByClassName

I have a table which contains 3 rows. Each row has the class: .myClass.
I then query for the table rows with document.getElementsByClassName('myClass') and iterate over the elements, changing each row's class to .otherClass.
However,
console.log(document.getElementsByClassName('otherClass'))
only returned one row.
And, when I looked at the DOM, only the first .myClass row had its class changed to .otherClass; the other remained untouched.
How can I change the class of all .myClass rows to .otherClass?
var c = document.getElementsByClassName('myTable')[0];
var x = c.getElementsByClassName('myClass');
for (var i = 0; i < x.length; i++) {
x[i].className = 'otherClass';
}
x = c.getElementsByClassName('otherClass');
console.log(x); // only one element
<table class="myTable">
<tr class="myClass2">
<td>Content</td>
<td>Content</td>
</tr>
<tr class="myClass">
<td>Content</td>
<td>Content</td>
</tr>
<tr class="myClass">
<td>Content</td>
<td>Content</td>
</tr>
</table>
getElementsByClassName, like other HTML collections, is "live", that is, when you assign another class name to its member, it's removed from the collection on the fly and its length gets decremented. That's why your loop runs only once.
var x = document.getElementsByClassName('myClass');
alert("before: " + x.length);
x[0].className='otherClass';
alert("after: " + x.length);
.myClass { color: black }
.otherClass { color: red }
<b class="myClass">hi</b>
<b class="myClass">hi</b>
Docs:
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
To answer in context to your question, you could set the className of the first element until there are none left in the collection:
while(x.length > 0) {
x[0].className = 'otherClass';
}
As georg pointed out in his answer, getElementsByClassName returns a "live" collection. That means the array will "update" as the elements change.
To fix your problem, you should use a while loop, iterating while x.length exists, and only changing the first element of the HTMLCollection.
var c = document.getElementsByClassName('myTable')[0];
var x = c.getElementsByClassName('myClass');
while (x && x.length) {
x[0].className = 'otherClass'
}
var y = c.getElementsByClassName('otherClass');
alert(y.length);
.myClass {
display:block;
background-color: red;
}
.otherClass {
display:block;
background-color:green;
}
<table class="myTable">
<tr class="myClass2">
<td>Content</td>
<td>Content</td>
</tr>
<tr class="myClass">
<td>Content</td>
<td>Content</td>
</tr>
<tr class="myClass">
<td>Content</td>
<td>Content</td>
</tr>
<table>
Georg is right. Elements array is updated on the fly, so you cannot depend on it's length;
Try this code:
var c = document.getElementsByClassName('myTable')[0],
x = c.getElementsByClassName('myClass');
while (x.length) {
x[0].className = 'otherClass';
}
var y = c.getElementsByClassName('otherClass');
alert(y.length);
Working fiddle

Remove <tr> if the <td> does not contain the value of the <input>

I'm trying to implement a live search (filtering) feature with jQuery for a table. The table contains a list of people and their grad year and high school. When the user starts typing inside the search input, the table will start filtering out all the rows that do not contain the value of the search input. It will also add the class of highlight to the td that the searched text was in.
How can I filter each row and highlight the td element when the user searches something? I tried implementing this with the code below but to no avail. What can I tweak in this code to get this working correctly?
Below is my code. Here is my jsFiddle: http://jsfiddle.net/mikerodriguez/jybrnt22/2/
jQuery
$("#search").on("keyup", function(){
var input = $(this).val();
$("#search_table tbody tr").each(function(){
var row = $(this);
var td_element = $("#search_table tbody tr td");
if(input !== td_element.text()){
row.hide();
}else{
row.show();
td_element().addClass("highlight");
}
})
});
CSS
body {
margin: 0;
padding: 0;
font-family: Arial;
font-size: 14px;
}
.search_field {
padding: 15px;
}
.search_field input[type="text"] {
padding: 15px;
width: 98%;
font-size: 18px;
}
.search_table_container {
padding: 15px;
}
.search_table {
width: 100%;
}
.search_table th {
background-color: #AAA;
font-weight: bold;
padding: 10px 0px;
}
.search_table td {
text-align: center;
background-color: #CCC;
padding: 15px 0px;
}
HTML
<div class="search_field">
<input type="text" id="search" placeholder="Search for Person, Class, or High School">
</div>
<div class="search_table_container">
<table id="search_table" class="search_table">
<thead>
<tr>
<th>Name</th>
<th>Class</th>
<th>High School</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Smith</td>
<td>2014</td>
<td>Some High School</td>
</tr>
<tr>
<td>Homer Simpson</td>
<td>2015</td>
<td>Springfield High School</td>
</tr>
<tr>
<td>Bugs Bunny</td>
<td>2050</td>
<td>Looney Tunes High School</td>
</tr>
<tr>
<td>George Washington</td>
<td>1749</td>
<td>Georgetown Academy</td>
</tr>
<tr>
<td>Marty McFly</td>
<td>1991</td>
<td>Back to the Future</td>
</tr>
<tr>
<td>Doc Emmet Brown</td>
<td>1965</td>
<td>One Point Twenty-one Gigawatts</td>
</tr>
</tbody>
</table>
</div>
One problem is:
input !== td_element.text()
You're comparing partial input values to the entire contents of your columns. Instead it should be something like
td_element.text().indexOf(input) == -1
But there were actually quite a few issues (including simple syntax errors, e.g., td_element is not a function). I tweaked your example to something that works: http://jsfiddle.net/gh5kjku5/2/
$("#search").on("keyup", function(){
var input = $(this).val();
$("#search_table tbody tr").each(function(){
var row = $(this);
var td_elements = row.find('td');
var colText = td_elements.text();
if(colText.indexOf(input) == -1){
row.hide();
}else{
row.show();
td_elements.addClass("highlight");
}
})});
You'll need to do a bit more work to do things like reset the td background colors when the search box is cleared. Good luck!
hi try this it's working.
$("#search").on("keyup", function () {
var input = $(this).val();
if (input == '') {
$("#search_table tbody tr").show();
} else {
$("#search_table tbody tr").show();
$("#search_table tbody tr").each(function () {
var row = $(this);
var td_element = $("#search_table tbody tr td");
if ($(row).text().trim().toUpperCase().indexOf(input.toUpperCase()) > -1) {
row.hide();
} else {
row.show();
}
});
}
});
see jsfiddle link http://jsfiddle.net/jybrnt22/14/

Pure Javascript table column hover effect?

I need a pure Javascript (no jQuery) hover effect for HTML table columns.
I found this which supposedly contains a fix for Firefox yet it still looks broken to me.
I found this which works only for the first column.
Unfortunately, my Javascript skills are amateur at best, so my attempts to modify either of these turned out to be fruitless.
Is this possible? Any suggestions would be appreciated.
Here's a column-based approach. When the mouse enters/leaves a cell, find the corresponding <col/> by index and apply/remove the desired class:
(() => {
const myTable = document.getElementById("myTable");
const cols = myTable.querySelectorAll("col");
const events = {
mouseover: e => {
const t = e.target.closest("td");
if (t) {
const cellIndex = t.cellIndex;
for (let i = 0, n = cols.length; i < n; i++) {
cols[i].classList[i === cellIndex ? "add" : "remove"]("hovered");
}
}
},
mouseout: e => {
const t = e.target;
if (t.nodeName === "TD" && !t.contains(e.relatedTarget)) {
cols[t.cellIndex].classList.remove("hovered");
}
}
};
for (let event in events) {
myTable.addEventListener(event, events[event]);
}
})();
.hovered {
background-color: #FF0000;
}
<table id="myTable" cellspacing="0">
<col />
<col />
<col />
<tbody>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2
<span>nested</span>
</td>
<td>Col3</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
</tbody>
</table>
See also:
Element.classList
Node.Contains()
Element.Closest()
Here are your codes (+ demo):
var HOVER_CLASS = 'hovered';
var hovered;
table.addEventListener('mouseover', function (e) {
if (e.target.tagName.toLowerCase() == 'td') {
var index = e.target.cellIndex;
hovered && hovered.forEach(function (cell) {
cell.classList.remove(HOVER_CLASS);
});
hovered = Array.prototype.map.call(
table.rows,
function (row) {
var i = index;
while (!cell && i >= 0) {
var cell = row.cells[i];
i -= 1;
}
return cell;
}
);
hovered.forEach(function (cell) {
cell.classList.add(HOVER_CLASS);
});
}
}, true);
table.addEventListener('mouseout', function (e) {
hovered && hovered.forEach(function (cell) {
cell.classList.remove(HOVER_CLASS);
});
hovered = null;
}, true);
Best method I can think of is to give each <td> a class name that identifies the column it's in. i.e. "col1, col2, etc"
Then you can use the document.getElementsByClassName("colX") function to get an array of those <td>s, loop through the array and modify the style. Warning, this may not work in older browsers that don't have a getElementsByClassName function, but there are workarounds you can find easily for that. The best of which would be to use jQuery, not sure why you're against it.
You create a class in css
.HoverTabla > tbody > tr:hover,
.HoverTabla > tbody > tr:focus {
background-color: #42C6F7;
}
and then you call it from the table in the html
<table class="table HoverTabla" id="tbl_Plan">
<thead>
<tr>
<th>Tipo de plan</th>
<th>Tiempo en días</th>
<th>Max. Usuario</th>
<th>Max. Capacidad</th>
<th>Max. Casos</th>
<th>Valor plan</th>
<th></th>
</tr>
</thead>
</table>
CSS-only answer I found after a little bit of googling: https://css-tricks.com/simple-css-row-column-highlighting/
Each cell (<td>) in the table is given some padding through pseudo elements, which is used to create the hover effect. To make sure the hover effect doesn't extend further than the table itself, an overflow: hidden is used.
The sub-title in the article summarizes it all: "The trick is using huge pseudo elements on the <td>s, hidden by the table overflow"
Try
<td onMouseOver="this.bgColor='yellow';" onMouseOut="this.bgColor='white';">
This will work, no javascript needed. So it should work even when people turn javascript off.
Jfiddle: http://jsfiddle.net/vJacZ/
​
Html:
​<table>
<tr>
<td class="column1">
Column1
</td>
<td class="column2">
Column2
</td>
</tr>
</table>
Css:
.column1{
color:black;
}
.column1:hover{
color:red;
}
.column2{
color:black;
}
.column2:hover{
color:green;
}

Categories

Resources