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>
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>
$(function () {
var people = [];
var ctCells = [], questionCells = [], userCells = [];
var $tBody = $("#userdata tbody");
$.getJSON('https://api.myjson.com/bins/18g7fm', function (data) {
$.each(data.ct_info, function (i, f) {
ctCells.push(`<td id=${f.id}>${f.id}</td><td>${f.name}</td>`);
var users = []
var question = []
f.Qid_info.forEach((x) => {
x.user_info.forEach((y) => {
//avoid duplicates
var foundUser = users.find((user) => {
return user.id === y.id
})
if (!foundUser) {
users.push(y)
}
})
})
f.Qid_info.forEach((x) => {
var foundQuestion = question.find((questions) => {
return questions.id === x.id
})
if (!foundQuestion) {
question.push(x)
}
})
$.each(question, function (i, question) {
ctCells.push(`<td colspan="2"> </td>`)
questionCells.push(`<td id=${question.id}>${question.id}</td><td>${question.isActive}</td><td>${question["is complex"]}</td><td>${question["is breakdown"]}</td>`);
})
$.each(users, function (i, user) {
var a = user.data.map(function (key) {
return key
})
// ctCells.push(`<td colspan="2"> </td>`)
// questionCells.push(`<td colspan="${lent+1}"> </td>`)
userCells.push(`<td><div style="display:flex; flex-direction:row">
${
users.forEach(val => {
`<div style="display:flex; flex-direction:column">
<div>${val.id}${val.name}</div>
<div>${val.updatedAt}</div>
<div style="display:flex; flex-direction:column">
${user.data.forEach(IN => {
`
<div style="display:flex; flex-direction:row">
<div><p>${console.log(IN.git_ids)}</p></div>
</div>
`
})}
</div>
</div>`
})
}
</div></td>`)
// userCells.push(`<td id=${user.id}>UserId--- ${user.id} UserName---- ${user.name}${a.map(value => {
// return `
// <div id="${user.id}" >
// <td><input type="checkbox" style="display: inline;"> </td>
// <td> <span id="text">${Object.keys(value)[0]}</span></td>
// <td> <textarea type="text" class="gitplc" placeholder="GitId">${ value.git_ids}</textarea> </td> j
// </div>
// `
// })
// }</td><td>${user.updatedAt}</td>`);
})
});
console.log(userCells)
$.each(ctCells, function (i) {
console.log(userCells)
$tBody.append(`<tr>${ctCells[i]}${questionCells[i]}${userCells[i]}</tr>`)
})
});
});
#scrlSec {
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
/* .checkSec { width: 60%; } */
.checkSec .tbl {
padding-top: 20px;
}
.checkSec td {
padding-left: 10px;
}
.checkSec .btnGreen {
color: white;
background-color: #4CAF50;
border: none;
padding: 15px 32px;
width: 100%;
text-decoration: none;
}
.checkSec .gitplc {
width: 80%;
}
.checkSec #text {
font-size: 14px;
}
.checkSec .tbl .colOne {
width: 50%;
float: left;
}
.checkSec .tbl .colTwo {
width: 50%;
float: right;
}
#user {
overflow: auto;
}
.flex-container {
display: flex;
}
th,
td {
font-weight: normal;
padding: 5px;
text-align: center;
width: 120px;
vertical-align: top;
}
th {
background: #00B0F0;
}
tr+tr th,
tbody th {
background: #DAEEF3;
}
tr+tr,
tbody {
text-align: left
}
table,
th,
td {
border: solid 1px;
border-collapse: collapse;
table-layout: fixed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id='userdata'>
<thead>
<tr>
<th colspan="2" id="ct">CT INFO</th>
<th colspan="4" id="que">Question</th>
<th id="user">User Info</th>
</tr>
<tr>
<th>CT ID</th>
<th>CT</th>
<th>Id</th>
<th>isActive</th>
<th>is Complex</th>
<th>is Breakdown</th>
<th>USER</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
I am printing json data in table format in html. But in users column i am getting undefined but when i print those variable in console that is printing correct value.
This is my json api . When i print value in foreach loop of user i am getting undefined but on console.log i have proper value printing in console.
https://api.myjson.com/bins/18g7fm
This is happening because you are using forEach() inside a template literal. forEach() returns undefined by default. Use map() function instead.
userCells.push(`<td><div style="display:flex; flex-direction:row">
${
users.map(val => {
return `<div style="display:flex; flex-direction:column">
<div>${val.id}${val.name}</div>
<div>${val.updatedAt}</div>
<div style="display:flex; flex-direction:column">
${user.data.map(IN => {
return `
<div style="display:flex; flex-direction:row">
<div><p>${console.log(IN.git_ids)}</p></div>
</div>
`
})}
</div>
</div>`
})
}
</div></td>`)
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>
I am implemented successfully the recursive table. Then I added the (click) method in the parent tr in order to call the child method to fetch data from database to display in the child tr.the problem is i am able to get the data in the child. but the child tr immediately appear and disappear.Could you please anyone help me on this to display the child tr when i click the parent tr.
sampletree() {
var = ele < HTMLTableElement > document.getElementById("tableid");
ele.addEventListener("click", (ev: MouseEvent) => {
var element = ev.target as HTMLElement;
if (element.tagName !== "A")
return false;
ev.preventDefault();
var row = element.closest("tr");
var cls = row.classList[0];
var lvl = +(cls.slice(-1)) + 1;
cls = cls.slice(0, -1) + lvl;
while ((row = nextTr(row)) && (row.className.includes(cls) || row.className.includes("open")))
row.classList.toggle("open");
});
function nextTr(row) {
while ((row = row.nextSibling) && row.nodeType != 1);
return row;
}
}
getTableParent1(): void {
this.service.getTableParent1()
.subscribe(TableParent1 => this.TableParent1 = TableParent1;
}
getChild(): void {
this.service.getTablechild1()
.subscribe(Tablechild1 => this.Tablechild1 = Tablechild11;
}
ngOnInit() {
this.TableParent1();
this.sampletree();
}
tbody>tr {
display: none;
}
/* Simplified */
tr.level0,
tr.open {
display: table-row;
}
/* Added colors for better visibility */
/* Added some more styling after comment */
tr td {
padding: 0.2em 0.4em;
}
tr td:first-of-type {
position: relative;
padding: 0.2em 1em;
}
tr td a {
color: #0e879a;
text-decoration: inherit;
position: relative;
left: -0.73em;
font-size: 19px;
}
tr.level1 td:first-of-type {
padding-left: 1.5em;
}
tr.level2 td:first-of-type {
padding-left: 2em;
}
<table class="table table-bordered table-hover" id="tableid">
<thead>
<tr>
<th>test1</th>
<th>test2</th>
</tr>
</thead>
<tbody>
<tr class="level0" *ngFor="let tavles of tables">
<td>+{{tavles.test2}}</td>
<td>{{tavles.test1}}</td>
</tr>
<tr class="level1" *ngFor="let child of tablechild">
<td>+{{child.test1}}</td>
<td>+{{child.test2}} </td>
</tr>
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>