I have an admin users table on a web app I'm building, and I want the admins to be able to make other people admins, validate, and delete accounts. But to make it mobile friendly, I want to hide two columns on mobile, but also provide a button for the user with the option of seeing everything if they want to. The issue is, it takes three button pushes to reveal the whole table (when it should only be one), and the button won't let me reverse the action. Here is the JS code:
const showTable = document.getElementById("showTable");
showTable.addEventListener("click", function() {
const hiddens = document.getElementsByClassName("tableHide");
for (h of hiddens) {
if (h.classList.contains("tableHide")) {
h.classList.remove("tableHide");
showTable.innerText = "Hide Table";
} else {
h.classList.add("tableHide");
}
}
});
.tableHide {
display: none;
}
<button type='button' id='showTable'>Show Table</button>
<table>
<thead>
<th>First Name</th>
<th class='tableHide'>Last Name</th>
<th class='tableHide'>Username</th>
<th>Validated</th>
<th>Admin</th>
<th></th>
</thead>
<tbody>
<tr id='1'>
<td>Joe</td>
<td class='tableHide'>Bob</td>
<td class='tableHide'>joebob#gmail.com</td>
<td><input type='checkbox' id='validated'><label for='validated'></label></td>
<td><input type='checkbox' id='isadmin'><label for='isadmin'></label></td>
<td class='delButCont'><button type='button' class='deleteButtons'>Delete</button></td>
</tr>
<tr id='2'>
<td>Bob</td>
<td class='tableHide'>Joe</td>
<td class='tableHide'>bobjoe#gmail.com</td>
<td><input type='checkbox' id='validated'><label for='validated'></label></td>
<td><input type='checkbox' id='isadmin'><label for='isadmin'></label></td>
<td class='delButCont'><button type='button' class='deleteButtons'>Delete</button></td>
</tr>
</tbody>
</table>
And a working JS fiddle with the issue: https://jsfiddle.net/7oh6rch3/1/
Where did I mess up in my logic?
Your mistake was the way you selected the HTML Elements and the way you assigned / removed the CSS classes. I'd use two css classes to solve this:
const showTable = document.getElementById("showTable");
showTable.addEventListener("click", function() {
const hiddens = document.getElementsByClassName("tableHide");
for (h of hiddens) {
if (h.classList.contains("mobile")) {
h.classList.remove("mobile");
showTable.innerText = "Hide Table";
} else {
h.classList.add("mobile");
}
}
this.innerHTML = this.innerHTML == 'Show Table' ? 'Hide Table' : 'Show Table';
})
.mobile
{
display: none;
}
<button type='button' id='showTable'>Show Table</button>
<table>
<thead>
<th>First Name</th>
<th class='tableHide mobile'>Last Name</th>
<th class='tableHide mobile'>Username</th>
<th>Validated</th>
<th>Admin</th>
<th></th>
</thead>
<tbody>
<tr id='1'>
<td>Joe</td>
<td class='tableHide mobile'>Bob</td>
<td class='tableHide mobile'>joebob#gmail.com</td>
<td><input type='checkbox' id='validated'><label for='validated'></label></td>
<td><input type='checkbox' id='isadmin'><label for='isadmin'></label></td>
<td class='delButCont'><button type='button' class='deleteButtons'>Delete</button></td>
</tr>
<tr id='2'>
<td>Bob</td>
<td class='tableHide mobile'>Joe</td>
<td class='tableHide mobile'>bobjoe#gmail.com</td>
<td><input type='checkbox' id='validated'><label for='validated'></label></td>
<td><input type='checkbox' id='isadmin'><label for='isadmin'></label></td>
<td class='delButCont'><button type='button' class='deleteButtons'>Delete</button></td>
</tr>
</tbody>
</table>
also updated your fiddle:
https://jsfiddle.net/7oh6rch3/2/
That's because the result of document.querySelectorAll is a live collection, so every time you remove the class tableHide from an element - it is also removed from the collection, which makes for skip an additional element.
You could copy the elements to an array to preserve the result of selection (to make it no live):
const hiddens = [...document.getElementsByClassName("tableHide")];
Related
I have a table with four columns Name, Age, Country and a checkbox. If the checkbox is clicked(true) the name value of the row is showed in a textarea.
I am not really sure how I can realise that.
A row:
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
if the checkbox is true the value "James" should be shown in a textarea.
Thank you all.
I believe you need to do this for multiple rows in a table.
First select all the checkboxes with Document.querySelectorAll() to attach the event (click) to all the checkboxes.
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
Inside the event (click) handler function target all the checked checkboxes to loop through them to get the relevant names using Array.prototype.map():
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Also it is not good practice to mix up th and td inside of the same tr element. You should place th inside of a thead and td inside of tbody element:
var cb = document.querySelectorAll('input[type=checkbox]');
cb.forEach(function(ck){
ck.addEventListener('click', function(el){
var checked = document.querySelectorAll(':checked');
var tArea = document.getElementById('myText');
tArea.value = Array.from(checked).map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
//or using spread syntax
//tArea.value = [...checked].map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
});
});
table, th, td {
border: 1px solid black;
}
<table>
<thead>
<tr>
<th>Sl</th>
<th>Name</th>
<th>No</th>
<th>Country</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">1</td>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td scope="row">2</td>
<td>John</td>
<td>15</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr>
</tbody>
</table>
<textarea id="myText"></textarea>
Try this:
[...document.querySelectorAll("input[type='checkbox']")].forEach(function (v){
v.addEventListener("change", function(){
document.querySelector("textarea").value = (this).checked ? (this).parentElement.parentElement.querySelector("td").innerHTML:'';
})});
<table>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea></textarea>
Few javascript lines would be ok for you need.
let input = document.querySelector('input');
input.addEventListener('change', e=> {
if(e.target.checked == true){
// retreive tags
let name = document.querySelector('.name');
let textarea = document.querySelector('.textarea');
// insert data
textarea.innerText += name.innerText
}
})
<table>
<tr>
<th scope="row">1</th>
<td class="name">James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea class="textarea"></textarea>
Since your table can have multiple rows, where each can have the checkbox set or not, the textarea could get zero, one or more names.
So you would need to listen the change event, and then iterate the rows to collect the names, to finally set the value of the textarea:
let textarea = document.querySelector("textarea");
let table = document.querySelector("table");
table.addEventListener("change", function (e) {
let names = [];
for (let row of table.rows) {
if (row.querySelector("input[type=checkbox]").checked) {
names.push( row.children[1].textContent);
}
}
textarea.value = names.join("\n");
});
<table><tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr><tr>
<th scope="row">2</th>
<td>Lucy</td>
<td>14</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr></table>
<textarea></textarea>
i have this dinamic data html table:
<table cellpadding="0" cellspacing="0" width="100%" class="table" id="tSortable">
<thead>
<tr>
<th><input type="checkbox" name="checkall"/></th>
<th width="Auto">Adresa Unica</th>
<th width="Auto">ID</th>
<th width="Auto">Status</th>
<th width="Auto">Time</th>
<th width="Auto">Date</th>
<th width="Auto">Interval I</th>
<th width="Auto">Duty</th>
<th width="Auto">Interval II</th>
<th width="Auto">Duty</th>
<th width="Auto">Interval III</th>
<th width="Auto">Duty</th>
<th width="Auto">Interval IV</th>
<th width="Auto">Duty</th>
<th width="Auto">Calendar</th>
<th width="Auto">Model</th>
<th width="Auto">Installation Address</th>
</tr>
</thead>
<tbody>
<?php
while($griddata=mysql_fetch_assoc($records))
{
echo"<tr>";
echo "<td><input type='checkbox' class='ck'/></td>";
echo"<td class='mac'>".$griddata{'adresaUnica'}."</td>";
echo"<td>".$griddata{'id'}."</td>";
echo"<td class='a_i'>".$griddata{'status'}."</td>";
echo"<td>".$griddata{'time'}."</td>";
echo"<td>".$griddata{'date'}."</td>";
echo"<td>".$griddata{'interval1'}."</td>";
echo"<td class='duty'>".$griddata{'duty1'}."</td>";
echo"<td >".$griddata{'interval2'}."</td>";
echo"<td class='duty'>".$griddata{'duty2'}."</td>";
echo"<td>".$griddata{'interval3'}."</td>";
echo"<td class='duty'>".$griddata{'duty3'}."</td>";
echo"<td>".$griddata{'interval4'}."</td>";
echo"<td class='duty'>".$griddata{'duty4'}."</td>";
echo"<td>".$griddata{'calendar'}."</td>";
echo"<td>".$griddata{'model'}."</td>";
echo"<td>".$griddata{'adresainstalare'}."</td>";
echo"</tr>";
}
?>
</tbody>
</table>
and this code .js that i use to get an alert of all the values from the td's with the class "mac"
$( document).ready(function(e)
{
$('#tSortable td.mac').each(function() {
var $this=$(this);
var value= $this.text();
alert(value);
});
});
what i want is an example on how to get the value of that cell based on the checkbox that i select .?
You can use jQuery's change function. The function is triggered when the state of the check boxes changes. Here is some example code:
// Triggers when a checkbox changes state
$('#tSortable td.mac').change(function() {
// Checks if this object is selected
if($(this).is(":checked")) {
alert($(this).text());
// You can also get a list of all siblings (The other TDs)
$(this).siblings();
}
}
Use the change event, then a conditional to see if it is checked: DEMO
$('body').on('change', 'input[type="checkbox"]', function(e){
if(this.checked) alert($(this).parent().next().text());
});
If you use dynamic elements remember to use event delegation by utilizing the .on() method.
$('.ck').change(function() {
// I deliberately using parents in case that some day you will reorder the columns
var txt = $(this).parents('tr').first().find('.mac').text();
$('#result').text('The text is: ' + txt);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table cellpadding="0" cellspacing="0" width="100%" class="table" id="tSortable">
<thead>
<tr>
<th><input type="checkbox" name="checkall" /></th>
<th>Adresa Unica</th>
<th>ID</th>
<th>Status</th>
<th>Time</th>
<th>Date</th>
<th>Interval I</th>
<th>Duty</th>
<th>Interval II</th>
<th>Duty</th>
<th>Interval III</th>
<th>Duty</th>
<th>Interval IV</th>
<th>Duty</th>
<th>Calendar</th>
<th>Model</th>
<th>Installation Address</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="checkOne" class="ck" /></td>
<td class="mac">Adresa Unica____1</td>
<td>ID____1</td>
<td>Status____1</td>
<td>Time____1</td>
<td>Date____1</td>
<td>Interval I____1</td>
<td>Duty____1</td>
<td>Interval II____1</td>
<td>Duty____1</td>
<td>Interval III____1</td>
<td>Duty____1</td>
<td>Interval IV____1</td>
<td>Duty____1</td>
<td>Calendar____1</td>
<td>Model____1</td>
<td>Installation Address____1</td>
</tr>
<tr>
<td><input type="checkbox" name="checkOne" class="ck" /></td>
<td class="mac">Adresa Unica____2</td>
<td>ID____2</td>
<td>Status____2</td>
<td>Time____2</td>
<td>Date____2</td>
<td>Interval I____2</td>
<td>Duty____2</td>
<td>Interval II____2</td>
<td>Duty____2</td>
<td>Interval III____2</td>
<td>Duty____2</td>
<td>Interval IV____2</td>
<td>Duty____2</td>
<td>Calendar____2</td>
<td>Model____2</td>
<td>Installation Address____2</td>
</tr>
</tbody>
</table>
<hr />
<div id="result"></div>
I have table like this:
<table border="1">
<tr align="left" valign="top">
<th>ID</th>
<th>NAME</th>
<th>VALUE</th>
</tr>
<tr align="left" valign="top">
<td>1</td>
<td>Item 1</td>
<td><button>-</button> 5 <button>+</button></td>
</tr>
</table>
It is generated by Php and all information are from MySql DB..
I would like to activate buttons "-" and "+", so when I click minus, value 5 (in this case) will became 4 or when I click plus value 5 will became 6, and also in MySql DB some external php file will change values in real time..
I tried with some AJAX scripts, but I am stuck..
Please help.. Thanks..
Try storing first the value in an HTML element like <span></span>, and assign class tag for the + and - button:
<table border="1">
<tr align="left" valign="top">
<th>ID</th>
<th>NAME</th>
<th>VALUE</th>
</tr>
<tr align="left" valign="top">
<td>1</td>
<td>Item 1</td>
<td><button class="minus">-</button> <span>5</span> <button class="plus">+</button></td>
</tr>
</table>
Then create the script:
$(document).ready(function(){
$(document).on("click", ".minus", function(){ /* WHEN MINUS IS CLICKED */
var elem = $(this); /* THE ELEMENT CLICKED */
var id = elem.parent().siblings(":first").text(); /* ID OF THIS ROW IN THE DATABASE */
var current_no = Number(elem.closest("td").find("span").html()); /* CURRENT VALUE OF THIS ROW */
var new_no = current_no - 1; /* REDUCE ONE VALUE */
elem.closest("td").find("span").html(new_no); /* REPLACE WITH THE NEW NUMBER INSIDE THE SPAN */
});
$(document).on("click", ".plus", function(){ /* WHEN PLUS IS CLICKED */
var elem = $(this); /* THE ELEMENT CLICKED */
var id = elem.parent().siblings(":first").text(); /* ID OF THIS ROW IN THE DATABASE */
var current_no = Number(elem.closest("td").find("span").html()); /* CURRENT VALUE OF THIS ROW */
var new_value = current_no + 1; /* ADD ONE VALUE */
elem.closest("td").find("span").html(new_no); /* REPLACE WITH THE NEW NUMBER INSIDE THE SPAN */
});
});
For updating the data in your MySQL database in real-time, you need to use AJAX.
$.ajax({ /* START AJAX */
type: "POST", /* METHOD TO USE TO PASS THE DATA */
url: "update.php", /* FILE DESTINATION OF THE DATA */
data: {"id": id, "value": new_value} /* THE DATA TO BE PASSED ON */
}); /* END OF AJAX */
On the update.php file, it must contain the UPDATE query:
/*** YOUR ESTABLISHED CONNECTION HERE ***/
$stmt = $connection->prepare("UPDATE table SET value = ? WHERE id = ?");
$stmt->bind_param("ii", $_POST["value"], $_POST["id"]);
$stmt->execute();
Here is a jsfiddle (but without the AJAX).
If you use a form to fetch this value, you can use the <input type="number" />:
<table border="1">
<tr align="left" valign="top">
<th>ID</th>
<th>NAME</th>
<th>VALUE</th>
</tr>
<tr align="left" valign="top">
<td>1</td>
<td>Item 1</td>
<td><input type="number" value="5" /></td>
</tr>
</table>
Modern web browsers will display buttons to decrease or increase the value.
Using JS/jQuery:
/* JS: */
var counter = 5;
$(".down").on("click", function() {
if (counter > 0) {
counter--;
$('.anumber').text(counter);
}
});
$(".up").on("click", function() {
counter++;
$('.anumber').text(counter);
});
<!-- HTML: -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr align="left" valign="top">
<th>ID</th>
<th>NAME</th>
<th>VALUE</th>
</tr>
<tr align="left" valign="top">
<td>1</td>
<td>Item 1</td>
<td>
<button class="down">-</button> <span class="anumber">5</span>
<button class="up">+</button>
</td>
</tr>
</table>
JSFiddle
Better if you can change your html and add some classes, check the following suggestion :
$(function(){
$('body').on('click' ,'.minus', function(){
var current_number = parseInt($(this).parent().find('.number').text());
current_number--;
$(this).parent().find('.number').text(current_number);
});
$('body').on('click' ,'.plus', function(){
var current_number = parseInt($(this).parent().find('.number').text());
current_number++;
$(this).parent().find('.number').text(current_number);
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr align="left" valign="top">
<th>ID</th>
<th>NAME</th>
<th>VALUE</th>
</tr>
<tr align="left" valign="top">
<td>1</td>
<td>Item 1</td>
<td>
<button class='minus'>-</button>
<span class='number'>5</span>
<button class='plus'>+</button>
</td>
</tr>
</table>
Hope this helps.
After browsing online for tutorials on Javascript show/hide I could only find examples on where all the columns were by default visible. I'm looking for a way to have some columns hidden by default (and allow them to be toggled on via a checkbox) and to have some columns shown by default (and allow them to be toggled off via a checkbox).
Is this possible?
For reference my table structure is as follows:
<table>
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mike</td>
<td>Dancer</td>
</tr>
</tbody>
</table>
Pure javascript:
HTML
<input type="checkbox" onclick="showhide(1, this)" checked="checked" /> Name<br />
<input type="checkbox" onclick="showhide(3, this)" checked="checked" /> Job<br />
JS
function showhide(column, elem){
if (elem.checked)
dp = "table-cell";
else
dp = "none";
tds = document.getElementsByTagName('tr');
for (i=0; i<tds.length; i++)
tds[i].childNodes[column].style.display = dp;
}
Pure JS fiddle example
Please consider using a javascript library as JQuery for such trivial things. You code could be as simple as:
HTML
<input type="checkbox" data-col="1" checked="checked" /> Name<br />
<input type="checkbox" data-col="2" checked="checked" /> Job<br />
jQuery JS:
$(function(){
$(':checkbox').on('change', function(){
$('th, td', 'tr').filter(':nth-child(' + $(this).data('col') + ')').toggle();
});
});
jQuery Fiddle example
Here's the toggle function (using jQuery):
function toggleColumns(column, state) {
var cells = $("table").find("th, td").filter(":nth-child(" + column + ")");
if (state)
cells.hide();
else
cells.show();
}
If you need that column hidden by default, you can call this function during onLoad.
Example http://jsfiddle.net/nynEd/
in your css you should have something like
.hidden{
display:none;
}
.shown{
display:block;
}
then in your html you should have something like
<table>
<thead>
<tr>
<th id="th1" class="shown">Name</th>
<th id="th2" class="shown">Job</th>
</tr>
</thead>
<tbody>
<tr>
<td id="td1" class="shown">Mike</td>
<td id="td2" class="shown">Dancer</td>
</tr>
</tbody>
</table>
you then have to implement a togle method that will change the visibility of the column
//id should be passhed as 1, 2, 3 so on...
function togleTable(id){
if(document.getElementById("th"+id).className == "shown"){
document.getElementById("th"+id).className = "hidden";
}
if(document.getElementById("td"+id).className == "shown"){
document.getElementById("td"+id).className = "hidden";
}
if(document.getElementById("th"+id).className == "hidden"){
document.getElementById("th"+id).className = "shown";
}
if(document.getElementById("td"+id).className == "hidden"){
document.getElementById("td"+id).className = "shown";
}
}
and then in the compobox onChange() event you should call the togleTable function passing as id the number of the row you want to show/hide
this is a good place to start i think.
Have fun
UPDATED
if you want to have more than one class for your rows dont forget you can also use this:
document.getElementById('id').classList.add('class');
document.getElementById('id').classList.remove('class');
There are many way out for this my option is using basic jquery functions like,
<input type="checkbox" id="opt1" checked/>col 1
<input type="checkbox" id="opt2"/>col 2
<table border="1" cellpadding="5">
<thead>
<tr>
<th>Name</th>
<th>Job</th>
<th id="col1">col 1</th>
<th id="col2">col 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mike</td>
<td>Dancer</td>
<td class="data1">data 1</td>
<td class="data2">data 2</td>
</tr>
</tbody>
</table>
This is your HTML code,
$(document).ready(function() {
if($("#opt1").is(":checked")){
$("#col1").show();
$(".data1").show();
}else{
$("#col1").hide();
$(".data1").hide();
}
if($("#opt2").is(":checked")){
$("#col2").show();
$(".data2").show();
}else{
$("#col2").hide();
$(".data2").hide();
}
$("#opt1").live('click', function() {
if($("#opt1").is(":checked")){
$("#col1").show();
$(".data1").show();
}else{
$("#col1").hide();
$(".data1").hide();
}
});
$("#opt2").live('click', function() {
if($("#opt2").is(":checked")){
$("#col2").show();
$(".data2").show();
}else{
$("#col2").hide();
$(".data2").hide();
}
});
});
This is a java-script code.
Please find working example
The columns which you want to hide should have attribute style="display:none" initially
My problem is when I clicked on "span cell 1" button the colspan is done properly, but the head td's are extended and the table layout is disturbed as in table size increases. Cant it manage the remaining column?
If I click in span cell 1 button then first td is span in first 3 header. then remaining td's should be in one header.
function function1() {
document.getElementById("myTableHeader").colSpan = "3";
}
function function2() {
document.getElementById("myTd1").colSpan = "3";
}
function function3() {
document.getElementById("myTd2").colSpan = "2";
}
function function4() {
document.getElementById("myTableHeader").colSpan = "1";
document.getElementById("myTd1").colSpan = "1";
document.getElementById("myTd2").colSpan = "1";
}
<table>
<tr>
<th align="center" bgcolor="blue" style="color:white;">First Header</th>
<th id="myTableHeader" bgcolor="green" style="color:white;" width="140">Second Header</th>
<th align="center" bgcolor="red" style="color:white;" width="140">Third Header</th>
<th align="center" bgcolor="gray" style="color:white;" width="140">Fourth Header</th>
</tr>
<tr>
<td id="myTd1">Cell 1 content</td>
<td>Cell 2 content</td>
<td id="myTd2">Cell 3 content</td>
<td>Cell 4 content</td>
</tr>
</table>
<input type="button" name="S1" value="Span Second Header" onClick="function1();">
<input type="button" name="S2" value="Span Cell 1" onClick="function2();">
<input type="button" name="S3" value="Span Cell 3" onClick="function3();">
<input type="button" name="S4" value="Restore" onClick="function4();">
but the ahead td's are extend.and table layout is disturb
This is how it should be. You need to delete the cell, which space would be occupied by spanning cell.
You may play with colspan/rowspan properties editing HTML in your editor, not with javascript, in order to better understand, how it works.