Assuming an example table:
<table>
<tr>
<th>Head 1</th>
<th>Head 2</th>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
<tr>
<td>Data 3</td>
<td>Data 4</td>
</tr>
<tr>
<td>Data 5</td>
<td>Data 6</td>
</tr>
<tr>
<td>Data 7</td>
<td>Data 8</td>
</tr>
</table>
I'm looking for the best technique to highlight the rows <= n, where n is the hovered over row (excluding the header row). For example, if the mouse is over
<tr>
<td>Data 5</td>
<td>Data 6</td>
</tr>
the following part of the table should be highlighted:
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
<tr>
<td>Data 3</td>
<td>Data 4</td>
</tr>
<tr>
<td>Data 5</td>
<td>Data 6</td>
</tr>
Any ideas how this effect could be achieved?
Basically, you could see the thing the opposite way : any tr after hovered tr should have no background:
test this :
table:hover tr {
background:gray;
}
table:hover tr:hover ~tr {
background:none;
}
DEMO
=============== EDITED from request in comments ================
React only on last element in row.
BEWARE :This option doesn't allow to click in cells but last one of each row.
table {
pointer-events:none;
}
table tr :last-child {
pointer-events:auto;
cursor: pointer;
}
Try this:
(fiddle: http://jsfiddle.net/5SLN3/)
$('tr').hover(
function(){
$(this).addClass('hover').prevAll().addClass('hover');
},
function(){
$(this).removeClass('hover').prevAll().removeClass('hover');
}
)
and the style:
<style>
tr.hover td{background-color:#888}
</style>
Since there is not previous selector, you need to sort of do the opposite. Add a hove to the tbody and chnage the color of the rows after the row that was chosen.
HTML:
<table class="hovTable">
<thead>
<tr>
<th>Head 1</th>
<th>Head 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
<tr>
<td>Data 3</td>
<td>Data 4</td>
</tr>
<tr>
<td>Data 5</td>
<td>Data 6</td>
</tr>
<tr>
<td>Data 7</td>
<td>Data 8</td>
</tr>
</tbody>
</table>
CSS:
.hovTable, tr, td, th {
border-collapse: collapse;
border: 1px solid black;
}
.hovTable tbody td {
background-color: #FFF;
}
.hovTable tbody:hover td {
background-color: #CCC;
}
.hovTable tbody:hover tr:hover ~ tr td {
background-color: #FFF;
}
Example:
JSFiddle
References:
General Sibling Selector
var nameOfRows = "row"
//useful when there are other tables in your document.
//use like this
//<table>
//...<tr name="row">...</tr><tr name="row">...</tr>...
var backgroundOriginal = "#ffffff"; //background when the row isn't selected
var backgroundHover = "#ff0000"; //background when the row is selected;
function setHigh (id)
{
var rows = document.getElementsByName(nameOfRows);
for (var i = 0; i < rows.length; i++)
{
rows[i].style.background = backgroundOriginal;
}
for (i = 0; i <= id; i++) {
rows[i].style.background = backgroundHover;
}
}
for (var i = 0; i < document.getElementsByName(nameOfRows).length; i++)
{
document.getElementsByName(nameOfRows)[i].onmouseover = setHigh(i);
}
Try this out. I've not tested it yet, but I think it should work!
Related
We have a table:
<table>
<tbody>
<tr>
<td>Column 1</td>
<td colspan="3">Column 2</td>
<td>Column 3</td>
<td colspan="99999">Column 4</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td id="target">C</td>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</tbody>
</table>
Using JavaScript or jQuery, how would we able to get the column element (or its index) of the first row that is spanning the cell with id "target"? I don't really want to use any box positioning method (is: getBoundingClientRect()) technique.
In this example, the associated cell element that is spanning "target" is the cell with text "Column 2".
Here is a solution for the case, that the second row also has colspans and there is no third row:
Iterate over the cells of the second row with a for loop and count their colspans until you find your target cell (if there is no colspan defined it is automatically '1'). Then iterate over the cells of the first row and count their colspans until the count is equal or bigger then the count of the second row. In that case you have found the desired head cell.
Working example:
const head_cells = document.querySelectorAll('#head-row td');
const target_cells = document.querySelectorAll('#target-row td');
let head_position = 0;
let target_position = 0;
for (i = 0; i < target_cells.length; i++) {
target_position += target_cells[i].colSpan;
if (target_cells[i].id === 'target') {
for (k = 0; k < head_cells.length; k++) {
head_position += head_cells[k].colSpan;
if (head_position >= target_position) {
console.log(head_cells[k].textContent);
break;
}
}
break;
}
}
<table>
<tbody>
<tr id="head-row">
<td>Column 1</td>
<td colspan="4">Column 2</td>
<td>Column 3</td>
<td colspan="99999">Column 4</td>
</tr>
<tr id="target-row">
<td>A</td>
<td colspan="2">B</td>
<td id="target">C</td>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</tbody>
</table>
<script>
function findHeader(cell) {
let count = cell.cellIndex + 1; // 3
for(let header of headers.cells) {
const colspan = +header.getAttribute('colspan') || 1;
count -= colspan;
if (count<1) return alert(header.textContent);
}
}
</script>
<table border=1>
<tbody>
<tr id="headers">
<td>Column 1</td>
<td colspan="3">Column 2</td>
<td>Column 3</td>
<td colspan="99999">Column 4</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td onclick="findHeader(this)">Click</td>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</tbody>
</table>
The following code gets all the tr tags in #mytable:
table = document.getElementById("myTable");
trs = table.getElementsByTagName("tr");
But if we want to get only tr tags whose display is not none, what should I do?
Thanks.
Not the best solution, but you can do this...
let tableRows = $("#my-table tr");
tableRows.map((i, obj)=>{
if($(obj).attr('style') != 'display: none;'){
// whatever you want to do here...
console.log(obj);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<table id="my-table">
<tbody>
<tr>
<td>data 1</td>
<td>data 2</td>
</tr>
<tr style="display: none;">
<td>data 3</td>
<td>data 4</td>
</tr>
<tr>
<td>data 5</td>
<td>data 6</td>
</tr>
<tr style="display: none;">
<td>data 7</td>
<td>data 8</td>
</tr>
<tr>
<td>data 9</td>
<td>data 10</td>
</tr>
</tbody>
</table>
You can use the :visible selector which is a jquery extension (https://api.jquery.com/visible-selector/) that allows seelction of elements based on display visibility.
In the following snippet - there are 3 tr's but the middle one is hidden with display:none. The console log targets the visible tr's and logs the number (2);
$(document).ready(function(){
const totalRows = $('#myTable tr');
const visibleRows = totalRows.filter(':visible');
console.log('total rows: '+ totalRows.length); // gives 3
console.log('visible rows: '+ visibleRows.length); // gives 2 - since one tr is hidden
})
.second-row {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable">
<tbody>
<tr class="first-row">
<td>row 1</td>
<td>row 1</td>
<td>row 1</td>
</tr>
<tr class="second-row">
<td>row 2</td>
<td>row 2</td>
<td>row 2</td>
</tr>
<tr class="third-row">
<td>row 3</td>
<td>row 3</td>
<td>row 3</td>
</tr>
</tbody>
</table>
Simple solution with VanillaJS
var elems = document.querySelectorAll('tr');
var noneElems = [];
elems.forEach(function (element) {
if (window.getComputedStyle(element).display == 'none') {
noneElems.push(element);
}
});
console.log( { noneElems } );
<table id="mytable">
<tr>
<td>Block</td>
<td>1</td>
</tr>
<tr style="display:none">
<td>None</td>
<td>1</td>
</tr>
<tr>
<td>Block</td>
<td>2</td>
</tr>
<tr style="display:none">
<td>None</td>
<td>2</td>
</tr>
</table>
I am trying to make a jQuery "plugin" to paginate records on a table. According to my own question I tried to make manually.
Also, I am trying to figure out how to display the page numbers correlatively according to the buttonSize.
$(document).ready(function() {
$('#tabla').pagination({
pageSize: 1,
buttonSize: 5,
target: '#paginacion',
template: `<nav class="text-center" aria-label="Page navigation">
<ul class="pagination" id="paginacion">
</ul>
</nav>`
});
});
$.fn.extend({
pagination: function($options) {
$el = this;
buttons = $options.buttonSize || 5;
htmlElement = $($options.template);
target = $(htmlElement).find($options.target);
rows = $($el).find('tbody tr');
initialPage = 1;
pagesAmount = Math.ceil(rows.length / $options.pageSize);
pages = [];
while(rows.length > 0) {
let page = rows.splice(0, $options.pageSize);
pages.push(page);
}
window.pages = pages;
window.currentPage = initialPage;
for(i=0; i<pagesAmount; i++) {
paginationHTML = `<li><a data-page="${i}" href="#">${i+1}</a></li>`;
target.append(paginationHTML);
}
$el.append(htmlElement);
$el.find('tbody').html(pages[window.currentPage-1]);
let scriptCode = `$('${$options.target} a').on('click', function() {` + "\n\t" +
`window.currentPage = $(this).attr('data-page'); ` + "\n\t" +
`$('#${$el.attr('id')} tbody').html(window.pages[window.currentPage]); ` + "\n" +
`$(this).parent().parent().find('li').each(function(item) { $(this).removeClass('active'); })` + "\n" +
`$(this).parent().addClass('active')` + "\n" +
`});` + "\n"
$('body').append($('<script>').html(scriptCode));
}
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tabla" class="table table-striped table-bordered">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Column1: Row 1</td>
<td>Column2: Row 1</td>
<td>Column3: Row 1</td>
<td>Column4: Row 1</td>
</tr>
<tr>
<td>Column1: Row 2</td>
<td>Column2: Row 2</td>
<td>Column3: Row 2</td>
<td>Column4: Row 2</td>
</tr>
<tr>
<td>Column1: Row 3</td>
<td>Column2: Row 3</td>
<td>Column3: Row 3</td>
<td>Column4: Row 3</td>
</tr>
<tr>
<td>Column1: Row 4</td>
<td>Column2: Row 4</td>
<td>Column3: Row 4</td>
<td>Column4: Row 4</td>
</tr>
<tr>
<td>Column1: Row 5</td>
<td>Column2: Row 5</td>
<td>Column3: Row 5</td>
<td>Column4: Row 5</td>
</tr>
<tr>
<td>Column1: Row 6</td>
<td>Column2: Row 6</td>
<td>Column3: Row 6</td>
<td>Column4: Row 6</td>
</tr>
<tr>
<td>Column1: Row 7</td>
<td>Column2: Row 7</td>
<td>Column3: Row 7</td>
<td>Column4: Row 7</td>
</tr>
<tr>
<td>Column1: Row 8</td>
<td>Column2: Row 8</td>
<td>Column3: Row 8</td>
<td>Column4: Row 8</td>
</tr>
</tbody>
</table>
I didn't use ES6 functions since our system is Microsoft based and it won't work on IE.
I am not sure how to adjust the button size so if I have two hundred rows it won't display two hundred pages.
Any suggestions?
Is there a simple way of swapping elements of an html table using javascript?
for instance having a table like this:
<table>
<tr>
<td class = "draggable">
<div class = "droppable">Item 1</div>
</td>
</tr>
<tr>
<td class = "draggable">
<div class = "droppable">Item 2</div>
</td>
</tr>
I want to make it available to swap cells.
Thanks!
I've written a little function to swap elements. Pass as arguments the parent (container of swapping elements), and two numbers (index) of the children elements that you want to be swapped.
var rowsParent = document.getElementById('sortRows');
var cellsParent = document.getElementById('sortCells');
swapElements(rowsParent,0,1);
swapElements(cellsParent,2,0);
function swapElements(parent,elemA,elemB){
//a little of validation
if(!parent||parent.constructor.toString().search('HTML')===-1) return;
var children = parent.children;
if(typeof elemA!=='number' || typeof elemB!=='number' || elemA===elemB || !children[elemA] || !children[elemB]) return;
elemB = elemA<elemB ? elemB--:elemB;
var childNumb = children.length - 1;
var a = parent.removeChild(children[elemA]);
var b = parent.removeChild(children[elemB]);
append(elemB,a);
append(elemA,b);
function append(a,b){
childNumb===a ? parent.appendChild(b) : parent.insertBefore(b,children[a]);
}
}
table, td {
border: solid 1px black;
padding: 3px;
margin: 15px;
}
<table>
<tbody id="sortRows">
<tr>
<td>a 1</td>
<td>a 2</td>
<td>a 3</td>
<td>a 4</td>
<td>a 5</td>
</tr>
<tr id="sortCells">
<td>b 1</td>
<td>b 2</td>
<td>b 3</td>
<td>b 4</td>
<td>b 5</td>
</tr>
<tr>
<td>c 1</td>
<td>c 2</td>
<td>c 3</td>
<td>c 4</td>
<td>c 5</td>
</tr>
<tr>
<td>d 1</td>
<td>d 2</td>
<td>d 3</td>
<td>d 4</td>
<td>d 5</td>
</tr>
<tr>
<td>e 1</td>
<td>e 2</td>
<td>e 3</td>
<td>e 4</td>
<td>e 5</td>
</tr>
</tbody>
</table>
You could do it in the same way you swap contents for any variable:
var child1_HTML = $("table tr:nth-child(1)").html();
$("table tr:nth-child(1)").html($("table tr:nth-child(2)").html());
$("table tr:nth-child(2)").html(child1_HTML);
I want to invert table tbody rows with jQuery.
WHAT I HAVE:
<table width="630" border="0" cellspacing="0" cellpadding="0">
<thead>
<tr>
<td>TITLE A</td>
<td>TITLE B</td>
(...) continue in jsfiddle.
Here what I have and what I want: http://jsfiddle.net/ZaUrP/1/
fiddle
pretty much the same as the other guy, only I use .detach() which is guarunteed to keep any crazy events that were attached to the trs intact. I also use $.makeArray to avoid reversing any of the proto stuff on the base jQuery object.
$(function(){
$("tbody").each(function(elem,index){
var arr = $.makeArray($("tr",this).detach());
arr.reverse();
$(this).append(arr);
});
});
Try this:-
Get the array of trs from tbody using .get() and use Array.reverse to reverse the elements and assign it back.
var tbody = $('table tbody');
tbody.html($('tr',tbody).get().reverse());
Fiddle
In case you have events to tr or any containing elements you could just attach it using delegation, so that the reversed elements also get them delegated.
Demo
$('tbody').each(function(){
var list = $(this).children('tr');
$(this).html(list.get().reverse())
});
Demo --> http://jsfiddle.net/ZaUrP/5/
I wrote a jQuery plugin called $.reverseChildren which will reverse all the specified children of a given element. Credit goes to DefyGravity for his insightful and intriguing use of $.makeArray.
I have not only reversed the rows of a table, but also the columns.
(function($) {
$.fn.reverseChildren = function(childSelector) {
this.each(function(el, index) {
var children = $.makeArray($(childSelector, this).detach());
children.reverse();
$(this).append(children);
});
return this;
};
}(jQuery));
$(function() {
var tableCopy = $('#myTable').clone(true).attr('id', 'myTableCopy').appendTo(
$('body').append('<hr>').append($('<h1>').html('Reversed Table')));
tableCopy.find('tr').reverseChildren('th, td'); // Reverse table columns
tableCopy.find('tbody').reverseChildren('tr'); // Reverse table rows
});
* { font-family: "Helvetica Neue", Helvetica, Arial; }
h1 { font-size: 16px; text-align: center; }
table { margin: 0 auto; }
th { background: #CCC; padding: 0.25em; }
td { border: 1px solid #CCC; padding: 5px; }
hr { margin: 12px 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h1>Original Table</h1>
<table id="myTable" width="320" border="0" cellspacing="0" cellpadding="0">
<thead>
<tr> <th>Header A</th> <th>Header B</th> <th>Header C</th> </tr>
</thead>
<tbody>
<tr> <td>Data 1A</td> <td>Data 1B</td> <td>Data 1C</td> </tr>
<tr> <td>Data 2A</td> <td>Data 2B</td> <td>Data 2C</td> </tr>
<tr> <td>Data 3A</td> <td>Data 3B</td> <td>Data 3C</td> </tr>
<tr> <td>Data 4A</td> <td>Data 4B</td> <td>Data 4C</td> </tr>
</tbody>
</table>
I know this is late, but it can help some other users looking for an answer
function reverseTable() {
var table = document.getElementById("table")
var trContent = []
for (var i = 0, row; row = table.rows[i]; i++) {
trContent.push(row.innerHTML)
}
trContent.reverse()
for (var i = 0, row; row = table.rows[i]; i++) {
row.innerHTML = trContent[i]
}
}
table {border-collapse: collapse}
table, td {border: 1px solid black}
<html>
<body onload="reverseTable()">
Original Table
<table>
<tbody>
<tr>
<td>Cell 1,1</td>
<td>Cell 1,2</td>
<td>Cell 1,3</td>
</tr>
<tr>
<td>Cell 2,1</td>
<td>Cell 2,2</td>
<td>Cell 2,3</td>
</tr>
<tr>
<td>Cell 3,1</td>
<td>Cell 3,2</td>
<td>Cell 3,3</td>
</tr>
</tbody>
</table>
<br>
Reversed Table
<table id="table">
<tbody>
<tr>
<td>Cell 1,1</td>
<td>Cell 1,2</td>
<td>Cell 1,3</td>
</tr>
<tr>
<td>Cell 2,1</td>
<td>Cell 2,2</td>
<td>Cell 2,3</td>
</tr>
<tr>
<td>Cell 3,1</td>
<td>Cell 3,2</td>
<td>Cell 3,3</td>
</tr>
</tbody>
</table>
</body>
</html>