I want the 'adult' column moved to the last position (on the right) in the table, but the table is interactive, the number of columns is not fixed, and sometimes, there will be no 'adult' column.
Please help
Here's the table:
table.tableizer-table {
font-size: 12px;
border: 1px solid #CCC;
font-family: Arial, Helvetica, sans-serif;
}
.tableizer-table td {
padding: 4px;
margin: 3px;
border: 1px solid #CCC;
}
.tableizer-table th {
background-color: #104E8B;
color: #FFF;
font-weight: bold;
}
<table class="tableizer-table">
<thead><tr class="tableizer-firstrow"><th></th><th>adult</th><th>embryo</th><th>lava</th><th>pupa</th></tr></thead>
<tbody>
<tr><td>AAEL006466-RA</td><td>ns</td><td>ns</td><td>**</td><td>ns</td></tr>
<tr><td>AAEL006466-S2</td><td>***</td><td>ns</td><td>ns</td><td>ns</td></tr>
<tr><td>AAEL006466-S4</td><td>***</td><td>ns</td><td>*</td><td>ns</td></tr>
</tbody>
</table>
This function will reorder the columns so that the 'adult' column is put last (if it is present in any position in the table).
It does presume that there is AT MOST only one column headed 'adult' (having no 'adult' column is fine though):
$(function() {
function reorderTable() {
var adultCol;
var $headerCells = $(".tableizer-firstrow").children();
$headerCells.each(function(idx, el) {
var title = (el.textContent || el.innerText || "").toLowerCase();
if (title === 'adult') adultCol = idx;
});
if (adultCol) { // adult column is present
$(".tableizer-table tr").each(function(idx, el) {
$(this).append($(this).children().eq(adultCol));
});
}
};
reorderTable();
});
table.tableizer-table {
font-size: 12px;
border: 1px solid #CCC;
font-family: Arial, Helvetica, sans-serif;
}
.tableizer-table td {
padding: 4px;
margin: 3px;
border: 1px solid #CCC;
}
.tableizer-table th {
background-color: #104E8B;
color: #FFF;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableizer-table">
<thead>
<tr class="tableizer-firstrow">
<th></th>
<th>adult</th>
<th>embryo</th>
<th>lava</th>
<th>pupa</th>
</tr>
</thead>
<tbody>
<tr>
<td>AAEL006466-RA</td>
<td>ns</td>
<td>ns</td>
<td>**</td>
<td>ns</td>
</tr>
<tr>
<td>AAEL006466-S2</td>
<td>***</td>
<td>ns</td>
<td>ns</td>
<td>ns</td>
</tr>
<tr>
<td>AAEL006466-S4</td>
<td>***</td>
<td>ns</td>
<td>*</td>
<td>ns</td>
</tr>
</tbody>
</table>
EDIT Here's an explanation of how it works...
$(function() { // this waits for DOM to load fully before executing
function reorderTable() {
var adultCol; // this will be the column number that has the 'adult' header
var $headerCells = $(".tableizer-firstrow").children(); // gets the collection of <th> cells
$headerCells.each(function(idx, el) { // runs a function on each <th> cell
// The following is equivalent to writing $(el).text().toLowerCase() -
// to get the inner text so that we can compare it to our search phrase.
// But it is more entertaining to write and will run faster than jQuery's fn.
// It's job is to handle differences between browsers, and to ignore case for the comparison later
var title = (el.textContent || el.innerText || "").toLowerCase();
if (title === 'adult') adultCol = idx; // if we have a match, remember the column #
});
if (adultCol) { // run only if we found the `adult` column index (i.e. it is not null or undefined)
$(".tableizer-table tr").each(function() { // loop over EVERY table row (so both header and body)
// `this` is the current row, and $(this).append(...) will move an element (cell)
// to the last position in that row.
// the inner part says give me the nth cell to move.
// The nth cell being the 'adult' column.
$(this).append($(this).children().eq(adultCol));
});
}
};
reorderTable(); // execute the above function
});
Try the following code:
$(function() {
let firstColumnHeader;
let findPosToMove = $("table").find('tr')[0].cells.length - 2;
jQuery.each($("table tr"), function(index, value) {
if(index === 0){
firstColumnHeader = ($(this).children(":eq(1)")[index].innerText);
}
if(firstColumnHeader == 'adult'){
for(var i = 0; i < findPosToMove; i++){
$(this).children(":eq(1)").before($(this).children(":eq("+(findPosToMove+1)+")"));
}
}
});
});
table.tableizer-table {
font-size: 12px;
border: 1px solid #CCC;
font-family: Arial, Helvetica, sans-serif;
}
.tableizer-table td {
padding: 4px;
margin: 3px;
border: 1px solid #CCC;
}
.tableizer-table th {
background-color: #104E8B;
color: #FFF;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableizer-table">
<thead><tr class="tableizer-firstrow"><th></th><th>adult</th><th>embryo</th><th>lava</th><th>pupa</th></tr></thead>
<tbody>
<tr><td>AAEL006466-RA</td><td>ns</td><td>ns</td><td>**</td><td>ns</td></tr>
<tr><td>AAEL006466-S2</td><td>***</td><td>ns</td><td>ns</td><td>ns</td></tr>
<tr><td>AAEL006466-S4</td><td>***</td><td>ns</td><td>*</td><td>ns</td></tr>
</tbody>
</table>
Related
So, a few days ago, I posted this question (nearly identical) and received a very helpful response.
However, in order to make a table calculator, I already have a id set to every table row of a certain column to turn the table into a calculator, which kind of messes up the answer for the original question when I try to apply it for myself (the JavaScript parses the unit "kg" in with the number and displays a sum as "NaN").
As well, there is a visible text box displayed inside of every cell with the answer above, which looks kind of ugly. My current code has cells that don't appear as text boxes but are still editable, which makes for a much sleeker experience in my opinion (I know it makes no functional difference, but the appearance is something that bugs me a lot!)
Below is a mock-up of what I'd like the code to look like. I'm trying to make the numbers/input appear on the right side of the text box, but still on the left side of the unit ("kg").
Below is a mock-up of what I am trying to create (except the numbers would be on the right).
Here is the code I have:
<head>
<style>
table {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
margin: 5px;
width: 100%;
}
th, td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
margin: 5px;
padding: 5px;
}
</style>
</head>
<body>
<table>
<tr>
<th>header1</th>
<th>header2</th>
</tr>
<tr>
<td>entry1</td>
<td id="entry1" oninput="myFunction()">4000</td>
</tr>
<tr>
<td>entry2</td>
<td id="entry2" oninput="myFunction()">200</td>
</tr>
<tr>
<td>Total</td>
<td id="total"></td>
</tr>
</table>
<script type="text/javascript">
document.getElementById("entry1").contentEditable = true;
document.getElementById("entry2").contentEditable = true;
function myFunction() {
var entry1 = document.getElementById("entry1").innerText;
var entry2 = document.getElementById("entry2").innerText;
var total2 = parseInt(entry1) + parseInt(entry2);
document.getElementById("total").innerHTML = total2;
}
myFunction();
</script>
</body>
As you can see, it adds up the numbers in the right column and displays a sum in the final row. However, I would like units to display here (e.g. "kg") on the side, that aren't editable and, more importantly, don't get parsed as a number in the JavaScript function. Would be great if the ugly textbox outline doesn't appear inside the cell, too.
Is this possible? Any answers appreciated!
You get NaN when you call parseInt on an empty string. To fix this, change following statement from
var total = parseInt(jack2) + parseInt(john2) + parseInt (joe2);
to
var total = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt (joe2) || 0);
and to display the unit alongside the number in the right column, add 2 span elements inside the td element and use flexbox to align them properly.
To make the number editable, add contentEditable attribute on the span element containing the number. span element containing the unit will be non-editable by default.
function myFunction() {
var jack2 = document.getElementById("jack").innerText;
var john2 = document.getElementById("john").innerText;
var joe2 = document.getElementById("joe").innerText;
var total = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt(joe2) || 0);
document.getElementById("total").innerHTML = total;
}
myFunction();
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
margin: 5px;
}
th,
td {
padding: 5px;
}
td:last-child {
display: flex;
justify-content: space-between;
border: none;
}
td:last-child span:first-child {
flex-grow: 1;
margin-right: 10px;
outline: none;
text-align: right;
}
#total {
display: flex;
justify-content: flex-end;
}
<table>
<thead>
<tr>
<th>Person</th>
<th>Weight</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jack</td>
<td id="jack" oninput="myFunction()">
<span contentEditable="true">4</span>
<span>Kg</span>
</td>
</tr>
<tr>
<td>John</td>
<td id="john" oninput="myFunction()">
<span contentEditable="true">2</span>
<span>Kg</span>
</td>
</tr>
<tr>
<td>Joe</td>
<td id="joe" oninput="myFunction()">
<span contentEditable="true">3</span>
<span>Kg</span>
</td>
</tr>
<tr>
<td>Total</td>
<td id="total"></td>
</tr>
</tbody>
</table>
To avoid the result being "NAN", an if is added and we check the one of the seals is empty '' and replace it with a 0.
In the edit cell two divs are added one to edit the value and the other to add the text "kg".
<style>
table {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
margin: 5px;
width: 100%;
}
th, td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
margin: 5px;
padding: 5px;
}
.input_{
width: 90%;
float: left;
}
.peso{
width: 10%;
float: right;
}
</style>
<table>
<tr>
<th>Person</th>
<th>Weight</th>
</tr>
<tr>
<td>Jack</td>
<td>
<div class="input_" id="jack" oninput="myFunction()">1</div>
<div class="peso">kg</div>
</td>
</tr>
<tr>
<td>John</td>
<td>
<div class="input_" id="john" oninput="myFunction()">2</div>
<div class="peso">kg</div>
</td>
</tr>
<tr>
<td>Joe</td>
<td>
<div class="input_" id="joe" oninput="myFunction()">3</div>
<div class="peso">kg</div>
</td>
</tr>
<tr>
<td>Total</td>
<td id="total"></td>
</tr>
</table>
<script type="text/javascript">
document.getElementById("jack").contentEditable = true;
document.getElementById("john").contentEditable = true;
document.getElementById("joe").contentEditable = true;
function myFunction() {
var jack2 = document.getElementById("jack").innerText;
var john2 = document.getElementById("john").innerText;
var joe2 = document.getElementById("joe").innerText;
if(jack2==""){
jack2=0;
}
if(john2==""){
john2=0;
}
if(joe2==""){
joe2=0;
}
var total2 = parseInt(jack2) + parseInt(john2) + parseInt (joe2);
document.getElementById("total").innerHTML = total2+" kg";
}
myFunction();
</script>
I have this fiddle:
https://jsfiddle.net/n9epsy5x/2/
I've got drag and drop working for the column headers, but I'd like a header's whole column to move when dragging and dropping the header. How can I pull this off in plain Javascript (VanillaJS)?
I tried adding classes to the table headers and accompanying column elements to be able to target the column elements to get them to move, but I couldn't get that to work.
Any help would be greatly appreciated. Thanks!
var source;
function isbefore(a, b) {
if (a.parentNode == b.parentNode) {
for (var cur = a; cur; cur = cur.previousSibling) {
if (cur === b) {
return true;
}
}
}
return false;
}
function dragenter(e) {
var targetelem = e.target;
if (targetelem.nodeName == "TD") {
targetelem = targetelem.parentNode;
}
if (isbefore(source, targetelem)) {
targetelem.parentNode.insertBefore(source, targetelem);
} else {
targetelem.parentNode.insertBefore(source, targetelem.nextSibling);
}
}
function dragstart(e) {
source = e.target;
e.dataTransfer.effectAllowed = 'move';
}
[draggable] {
user-select: none;
}
body {
background-color: #fff;
color: #303;
font-family: sans-serif;
text-align: center;
}
li {
border: 2px solid #000;
list-style-type: none;
margin: 2px;
padding: 5px;
}
ul {
margin: auto;
text-align: center;
width: 25%;
}
<table>
<thead>
<tr>
<th ondragstart="dragstart(event)" ondragenter="dragenter(event)" draggable="true">
Column 1
</th>
<th ondragstart="dragstart(event)" ondragenter="dragenter(event)" draggable="true">
Column 2
</th>
<th ondragstart="dragstart(event)" ondragenter="dragenter(event)" draggable="true">
Column 3
</th>
</tr>
</thead>
<tbody>
<tr>
<td>hhgr</td>
<td>ffrr</td>
<td>qedf</td>
</tr>
<tr>
<td>wdfe</td>
<td>cjnb</td>
<td>cdke</td>
</tr>
<tr>
<td>awjb</td>
<td>cdjk</td>
<td>ijfe</td>
</tr>
</tbody>
</table>
I have an HTML table with different rows (TR) and when I click on one row the background color changes (if it blank it becomes blu and if it blue it becomes white).
How can I exclude from this onclick event the TR that have the TD with the class EXPANDREDUCE?
My code is the following but it doesn't work because in this way it works on each TR i click but I need to check if in the TR that I clicked there is one or more TD with the CLASS EXPANDREDUCE and if yes i don't need to do anything:
function rowHighlight() {
$("TR").click(function() {
try {
$(this).parent().prev()[0].tagName;
HighLightTR(this);
} catch (err) {}
});
}
By using the event.target property, like this:
$("tr").on("click", function(event) {
var tr = $(event.target);
});
NOTE: To check to see if it has the class EXPANDREDUCE, change your selector to "tr.EXPANDREDUCE".
Good luck.
Here's an example:
$(function() {
$("thead tr").addClass("background");
$("tbody tr:even").addClass("even");
$("tbody tr:odd").addClass("odd");
$("tbody input:checkbox:checked").parent().parent().addClass("sel");
$("tbody tr").click(function(e) {
var flag = $(this).hasClass("sel");
if (flag) {
$(this).removeClass("sel");
} else {
$(this).addClass("sel");
}
});
});
table {
width: 400px;
border: 2px solid #999;
text-align: center;
border-collapse: collapse;
}
table td, table th {
border: 2px solid #999;
height: 25px;
}
.background {
background-color: #CCC;
}
.even {
background-color: #FFE7BA;
}
.odd {
background-color: #FFF0F5;
}
.sel {
background-color: #FFFF00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<table>
<thead>
<tr>
<th>title</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
</tbody>
</table>
</div>
Question:
I have a HTML with type number i want to ge the value using jQuery create a range by adding 10% on either side then checking if each row falls in the range if not hide the row.
Code:
HTML
<input type="number" id="myPrice" onkeyup="myPriceFunction()" placeholder="Enter amount.." title="Type in a amount" min="0">
JavaScript/jQuery
$(document).ready(function(){
$("#myPrice").on("keyup", function() {
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
});
});
JS fiddle
https://jsfiddle.net/nx30zqjd/7/
Other:
I am using:
.addClass('discarded').hide();
.removeClass('discarded').show();
to hide and show rows
Expected Results:
I want the range to be created with priceLow and priceHigh then get price column get rid of $ and check if it falls within range if not hide using code above.
Update:
I added
$(this).closest('tr').removeClass('discarded').show();
} else {
$(this).closest('tr').addClass('discarded').hide();
}
however then this shows nothing because i don't check discarded rows, if i remove the check for discarded rows it doesn't apply my search to the range not sure if there is a easy way to have both but it seems to be ok for the moment
If you need any more information please ask.
Thanks
You can use this, you just need to iterate and get the values and then check, based on that you can hide and show.
$("#myPrice").on("keyup", function() {
if ($(this).val() === '') {
$("#myTable tr").show();
return;
}
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
$("#myTable tr td:nth-child(2)").each(function(e) {
var value = this.textContent.replace('$', '');
if (value >= priceLow && value <= priceHigh) {
$(this).closest('tr').show();
} else {
$(this).closest('tr').hide();
}
})
});
$(document).ready(function() {
});
$(document).ready(function() {
$("#myPrice").on("keyup", function() {
if ($(this).val() === '') {
$("#myTable tr").show();
return;
}
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
$("#myTable tr td:nth-child(2)").each(function(e) {
var value = parseFloat(this.textContent.replace('$', ''));
if (value >= priceLow && value <= priceHigh) {
$(this).closest('tr').removeClass('discarded').show();
} else {
$(this).closest('tr').addClass('discarded').hide();
}
})
});
});
<style>* {
box-sizing: border-box;
}
#mySearch {
background-image: url('https://www.w3schools.com/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th,
#myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
.show {
display: block;
}
a {
color: blue;
text-decoration: none;
/* no underline */
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>CPUs</h2>
CPU
Motherboards
<input type="number" id="myPrice" placeholder="Enter amount.." title="Type in a amount" min="0">
<input type="text" id="mySearch" placeholder="Search for cpus.." title="Type in a cpu name">
<table id='myTable'>
<thead>
<tr>
<th>CPU</th>
<th>Price</th>
<th>Mark</th>
<th>Value</th>
<th>Socket</th>
<th>Image</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href='mobo.php?cpu_name=AMD Ryzen 5 2600"' target='_blank'>AMD Ryzen 5 2600</a></td>
<td>$246.05</td>
<td>13537</td>
<td>55.02</td>
<td>AM4</td>
<td><img src=NA height='42' width='42'></td>
</tr>
</tbody>
<tbody>
<tr>
<td><a href='mobo.php?cpu_name=Intel Core i7-8700K"' target='_blank'>Intel Core i7-8700K</a></td>
<td>$585.90</td>
<td>15957</td>
<td>27.24</td>
<td>LGA1151</td>
<td><img src=". $row[" url "]." height='42' width='42'></td>
</tr>
</tbody>
</table>
My question is similar to THIS question, but I'm unable to use divs instead of colspans with a table.
It appears to be an issue that only appears in chrome, but I need to find a workaround.
My use case is very similar to the one below. Notice how the top border for 3.3 spans two columns, which is clearly not right. In my use case, the user is able to change which cells are merged so I can't set the border for a specific cell.
How do you set a cell's border to be confined to its own cell instead of sharing with a common cell whose colspan is greater than 1?
HTML
<div style="padding: 10px">
<table>
<tr>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
<td>1.4</td>
<td>1.5</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td colspan="2">2.3</td>
<td>2.5</td>
</tr>
<tr>
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
<td>3.4</td>
<td>3.5</td>
</tr>
<tr>
<td>4.1</td>
<td>4.2</td>
<td>4.3</td>
<td>4.4</td>
<td>4.5</td>
</tr>
<tr>
<td>5.1</td>
<td>5.2</td>
<td>5.3</td>
<td>5.4</td>
<td>5.5</td>
</tr>
</table>
</div>
CSS
table {
table-layout: fixed;
border-spacing: 0;
border-collapse: collapse;
}
td {
border: 1px solid lightgrey;
height: 60px;
width: 60px;
text-align: center;
vertical-align: middle;
}
td.active {
border: 1px solid blue;
}
td.brdr-b-hide {
border-bottom: none;
}
td.brdr-r-hide {
border-right: none;
}
JavaScript
var fnActivate = function(target) {
target.addClass('active');
if(!target.is(':first-child')) {
target.prev().addClass('brdr-r-hide')
}
var tr = target.closest('tr');
if(!tr.is(':first-child')) {
var prevTr = tr.prev();
$('td', prevTr).eq($('td', tr).index(target)).addClass('brdr-b-hide');
}
};
var fnDeactivate = function(target) {
target.removeClass('active');
if(!target.is(':first-child')) {
target.prev().removeClass('brdr-r-hide')
}
var tr = target.closest('tr');
if(!tr.is(':first-child')) {
var prevTr = tr.prev();
$('td', prevTr).eq($('td', tr).index(target)).removeClass('brdr-b-hide');
}
}
$('table').on('click', 'td', function(e){
var target = $(e.currentTarget);
if(e.ctrlKey && target.hasClass('active')){
fnDeactivate(target);
} else if(e.ctrlKey) {
fnActivate(target);
} else {
fnDeactivate($('table td.active'));
fnActivate(target);
}
});
CODE: Plunkr
Issue was fixed by using:
table {
border-collapse: separate;
}
Code: Plunkr
It's a little different on the front end as each cell now has its own border of 1px, but it's a good workaround for the time being.
I think this usecase is best adressed with the outline css property.
See: http://jsfiddle.net/4zxv4o59/
td.active {
outline: 1px solid blue;
}
Outlines do not take up space, they are drawn above the content.
from https://developer.mozilla.org/en/docs/Web/CSS/outline