HTML - JS - multiple buttons that change css of table columns - javascript

I have a HTML document with a table in it
<table>
<tr>
<th class="street">Street</th>
<th class="city">City</th>
<th class="country">Country</th>
</tr>
<tr>
<td class="street">street-1</td>
<td class="city">city-1</td>
<td class="country">country-1</td>
</tr>
<tr>
<td class="street">street-2</td>
<td class="city">city-2</td>
<td class="country">country-2</td>
</tr>
</table>
Now I am looking for a way to implement buttons.
For example
<button id="button_street">TOGGLE STREET</button>
<button id="button_city">TOGGLE CITY</button>
<button id="button_country">TOGGLE COUNTRY</button>
If a button is pressed, the corresponding column in the table should be hidden.
Even better (than hidden) it would be if I could change the css design with the buttons.
My (temporary) solution is quite cumbersome...
It's a javascript solution that changes one class (visible) to another (hidden).
Spry.Utils.addLoadListener(function() {
let buttonToggle = document.getElementById('button_street');
buttonToggle.addEventListener('click', toggleClass);
function toggleClass() {
let collection = document.getElementsByClassName("street");
for (var i=0; i<collection.length; i++) {
collection[i].classList.toggle('street_design2');
}
}
}
This javascript must be repeated for each button.
where the css is the following:
.street {
background-color: blue;
}
.street_design2 {
background-color: red;
}
If I want to hide the "street-column" I can use display: none
I haven't found any other javascript solution to address all elements with class street. Maybe there is a better solution?
also it would be good if i could pass the function to an array like this:
const array = ["street", "city", "country"]
instead of repeating it for each button. Maybe there is a solution (a loop?)?

You can use document.querySelectorAll to address all elements with same tagName, class, etc, and then use .forEach() to add the EventListener to all elements at once for your case.
function toggleClass(collection) {
document.querySelectorAll('.' + collection).forEach(function(element) {
element.classList.toggle(collection + '_design2');
});
}
document.querySelectorAll('button').forEach(function(button) {
button.addEventListener('click', function(e) {
let collection = this.id.split('_').pop();
toggleClass(collection);
});
});
.street {
background-color: blue;
}
.street_design2 {
background-color: red;
}
.city_design2 {
background-color: yellow;
}
.country_design2 {
background-color: green;
}
<table>
<tr>
<th class="street">Street</th>
<th class="city">City</th>
<th class="country">Country</th>
</tr>
<tr>
<td class="street">street-1</td>
<td class="city">city-1</td>
<td class="country">country-1</td>
</tr>
<tr>
<td class="street">street-2</td>
<td class="city">city-2</td>
<td class="country">country-2</td>
</tr>
</table>
<button id="button_street">TOGGLE STREET</button>
<button id="button_city">TOGGLE CITY</button>
<button id="button_country">TOGGLE COUNTRY</button>

You can use the data property to specify which node to target. It will help in avoiding the name conflicts in the future and also callback will only execute for the specific button where data-table-toggle property is specified so it will avoid conflicts with other buttons.
Code will adds an event listener to all the buttons in a web page that have a custom data attribute "data-table-toggle". When the user clicks on one of these buttons, the tableToggle() function is executed.
The tableToggle() function first retrieves the value of the "data-table-toggle" attribute of the clicked button using this.getAttribute("data-table-toggle"). It then uses this value to select all the table rows that have a class attribute matching the value of the "data-table-toggle" attribute. This is done using the document.querySelectorAll() method with a CSS selector string that targets all the elements that have a child element with the specified class.
Finally, the function toggles the class of each selected table row between two different styles: the original class associated with the value of "data-table-toggle" attribute and a new class with "-_design2" appended to it. This is done using the classList.toggle() method.
Overall, this code dynamically modifies the styles of table rows based on the clicked button, allowing for a simple toggle effect.
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.2/axios.min.js" integrity="sha512-NCiXRSV460cHD9ClGDrTbTaw0muWUBf/zB/yLzJavRsPNUl9ODkUVmUHsZtKu17XknhsGlmyVoJxLg/ZQQEeGA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="script.js"></script>
<style>
table .street-_design2 {
display:none;
}
table .city-_design2 {
display:none;
}
table .country-_design2 {
display:none;
}
</style>
</head>
<body>
<table>
<tr>
<th class="street">Street</th>
<th class="city">City</th>
<th class="country">Country</th>
</tr>
<tr>
<td class="street">street-1</td>
<td class="city">city-1</td>
<td class="country">country-1</td>
</tr>
<tr>
<td class="street">street-2</td>
<td class="city">city-2</td>
<td class="country">country-2</td>
</tr>
</table>
<button data-table-toggle="street">TOGGLE STREET</button>
<button data-table-toggle="city">TOGGLE CITY</button>
<button data-table-toggle="country">TOGGLE COUNTRY</button>
</body>
window.onload = function () {
Array.from(document.querySelectorAll("button")).forEach(function (element) {
if (!element.getAttribute("data-table-toggle")) return;
element.addEventListener('click', tableToggle);
});
function tableToggle() {
const attribute = this.getAttribute("data-table-toggle");
Array.from(document.querySelectorAll(`tr .${attribute}`)).forEach(function (selector) {
selector.classList.toggle(`${attribute}-_design2`);
})
}
};

Related

How do I display the content of closest <td> on javascript?

I have looked everywhere, but my code does not work at all. I simply want to display the content of the td I'm clicking on.
I have this table:
<tr class='rowData' tooltip='{caracteristicas}'>
<td nowrap class='Body'><a href='{caracteristicas}' target="_blank" style="color:black" onClick='return confirm("VOCÊ SERÁ REDIRECIONADO PARA:\r\r {caracteristicas}")'>{inputDescItem}</a></td>
<td nowrap class='Body' align='right'>{quantidade} {hiddenCodigoItem}</td>
<td nowrap class='Body' align='center'>{grupoEstoque}</td>
<td nowrap class='Body' align='center'>{inputCodigoItem}</td>
<td nowrap class='Body' align='center'>{btnAtualizaItem}</td>
<td nowrap class='Body' align='center'><button type="button" class="btnTest">Assign</button></td>
<td nowrap class='Body' align='center' class="testNameClass" name="output" style="display:none;">{caracteristicas}</td>
</tr>
I want it so that when I click on the CLICK ME tag, it will display (in a pop-up, alert, modal or anything) the content of the below tag (that I'm not displaying).
I have the following javascript:
$("btnTest").on("click", function() {
alert($(this).closest('tr').find('testNameClass').val());
});
I'm not very good at JS so please go easy on me.
Look like you missing
$(".btnTest") instead of $("btnTest")
and just try
$(".btnTest").on("click", function() {
alert($(this).parents('tr').find('.testNameClass').val());
});
To target specific elements using a class you need to use a dot in front of the class name. In your case .btnTest and .testNameClass.
$(".btnTest").on("click", function() {
alert($(this).closest('tr').find('.testNameClass').text());
});
As you are looking for the text inside the td element you should use .text() instead of .val()
In the below example column ent_3 is hidden and you will get its values using the script mentioned above.
$(".btnTest").on("click", function() {
alert($(this).closest('tr').find('.testNameClass').text());
});
.testNameClass {
display: none;
}
table {
border-collapse: collapse;
}
th, td { border: 1px solid #000; padding: 10px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-bordered" id="dataTable">
<thead>
<tr>
<th>pk</th>
<th>ent_1</th>
<th>ent_2</th>
<th>ent_3</th>
</tr>
</thead>
<tbody>
<tr>
<td>PK Row 0</td>
<td>Ent_1</td>
<td><button type="button" class="btnTest">Assign</button></td>
<td class="testNameClass">Row 0 Ent_3</td>
</tr>
<tr>
<td>PK Row 1</td>
<td>Ent_1</td>
<td><button type="button" class="btnTest">Assign</button></td>
<td class="testNameClass">Row 1 Ent_3</td>
</tr>
<tr>
<td>PK Row 2</td>
<td>Ent_1</td>
<td><button type="button" class="btnTest">Assign</button></td>
<td class="testNameClass">Row 2 Ent_3</td>
</tr>
</tbody>
</table>
Your method will be handed a reference to the MouseEvent which represents details of the click. Since it is an Event, it has a currentTarget which represents an "element" in the so-called DOM ... an internal data-structure which represents the HTML. This data structure is in the form of a tree, where each node has one parent, two siblings, and some children. You can now write code to "walk up the tree" until you encounter a td node. The first one you come to is the innermost containing td.
I think you are targeting is incorrect use a . before the class name - also I see two classes in one element I set this up for you here have a look
https://jsfiddle.net/hw0ansyj/1/
$(".btnTest").on("click", function() {
alert($('.testNameClass').html());
});

Element in div gets removed as a child but can't be used again

I am trying to display a hidden table in a div then hide it again with display: none/block toggle. It works. But, I can't get it to appear again once I toggle to display: none to hide it.
HTML:
The HTML has an empty div with id = tableContainer.
Next to it, I have a table with the names of animal families in each cell, along with a button. When the button is clicked, it takes the name of the animal family from that particular cell, finds the table of animal species with that name and switches from display: none to display:block and display it /inside the div. Then, if I click the button again, it toggles the display back to display: none.
When I click a button in another cell, it clears the div and displays the new table.
All good.
But, if I click a button that was previously used, the table that has now gone is no longer available.
I have gone through all sorts of hoops playing with removeChild and all that but no luck. I am currently using innerHTML to clear the div, but I'm missing something with the class name.
Console error says: tabletest2.html:523 Uncaught TypeError: Cannot read property 'classList' of null
at toggle (tabletest2.html:523)
at HTMLButtonElement.onclick (tabletest2.html:72)
So, it seems to me that it can't toggle any more because the table now no longer exists, or I may be wrong with that as I didn't delete the child element (I think).
<body>
<table>
<tbody>
<tr>
<td>Genus</td>
<td>Benthobatis
<button onclick="toggle(this, parentNode.firstChild)">Click me</button></td>
</tr>
<tr>
<td>Genus</td>
<td>Diplobatis
<button onclick="toggle(this, parentNode.firstChild)">Click me</button></td>
</tr>
</tbody>
</table>
<!-- <======== div display container here ================>-->
<div id="tableContainer"></div>
<table id="Benthobatis" class="hide">
<tbody>
<tr>
<th>Genus</th>
<th>Benthobatis</th>
</tr>
<tr>
<td>Benthobatis kreffti</td>
<td>Brazilian Blind Electric Ray</td>
</tr>
</tbody>
</table>
<!-- <==================================-->
<table id="Diplobatis" class="hide">
<tbody>
<tr>
<th>Genus</th>
<th> Diplobatis </th>
</tr>
<tr>
<td>Diplobatis colombiensis</td>
<td>Colombian electric ray</td>
</tr>
</tbody>
</table>
</body>
<script>
function toggle(ele, tableName) {
var myTableDisplayDiv = document.getElementById("tableContainer").childNodes;
if (myTableDisplayDiv.length != 0) {
document.getElementById("tableContainer").innerHTML = "";
}
var myTableName = tableName.textContent;
var myTable = document.getElementById(myTableName);
myTable.classList.toggle("hide");
document.getElementById("tableContainer").appendChild(
document.getElementById(myTableName)
);
}
</script>
<style>
.hide {
display: none;
}
Explanations
"Why are my tables deleted if I'm only changing display option, not removing the child node?".
This destroys everything within:
document.getElementById("tableContainer").innerHTML = "";
This moves the chosen table to #tableContainer:
document.getElementById("tableContainer").appendChild(
document.getElementById(myTableName)
So in three clicks there's nothing left. Of course this is if the table can be identified correctly which it wasn't. The .textContent of .parentNode.firstChild reference was lost because this refers to a global context not the button. This is why on-event attributes (among other various reasons) are discouraged. Although not a critical issue as the ones previously mentioned, you should seriously have some variations to the names:
tableName
myTableName
myTable
myTableDisplayDiv
tableContainer
I'm pretty sure this naming scheme did not facilitate debugging.
Solutions
Before you place a table into #tableContainer where it gets destroyed, make a copy with .cloneNode().
Remove the onclick attributes and either use onclick property (like in the demo) or .addEventListener().
Register an ancestor element of both buttons (i.e. tbody), from there both buttons can be clicked and easily isolated and referenced by using event.target.
Now the reference to the clicked button (event.target) can now be referenced:
var tableName = event.target.parentNode.firstChild.textContent
And then the table can finally be referenced:
var table = document.getElementById(tableName)
Demo
document.querySelector('tbody').onclick = toggle;
function toggle(event) {
var clicked = event.target;
if (clicked.tagName === 'BUTTON') {
var genus = clicked.parentNode.firstChild.textContent;
var table = document.querySelector('#' + genus);
var display = document.getElementById("display");
display.innerHTML = "";
var clone = table.cloneNode(true);
display.appendChild(clone);
clone.classList.toggle('hide');
}
}
.hide {
display: none;
}
<table>
<tbody>
<tr>
<td>Genus</td>
<td>Benthobatis
<button>Click me</button></td>
</tr>
<tr>
<td>Genus</td>
<td>Diplobatis
<button>Click me</button></td>
</tr>
</tbody>
</table>
<!-- <======== div display container here ================>-->
<div id="display"></div>
<table id="Benthobatis" class="hide">
<tbody>
<tr>
<th>Genus</th>
<th>Benthobatis</th>
</tr>
<tr>
<td>Benthobatis kreffti</td>
<td>Brazilian Blind Electric Ray</td>
</tr>
</tbody>
</table>
<!-- <==================================-->
<table id="Diplobatis" class="hide">
<tbody>
<tr>
<th>Genus</th>
<th> Diplobatis </th>
</tr>
<tr>
<td>Diplobatis colombiensis</td>
<td>Colombian electric ray</td>
</tr>
</tbody>
</table>
Your code is kind of complex to understand but if you just want to toggle the table, I think this is the best way.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.hide {
display: none;
}
</style>
</head>
<body>
<div class="table-container">
<button class="toggle-btn">Click me</button>
<table>
<tr>
<td>Genus</td>
<td>Benthobatis</td>
</tr>
<tr>
<td>Genus</td>
<td>Diplobatis</td>
</tr>
</table>
</div>
<script>
const table = document.querySelector('table'),
btn = document.querySelector('.toggle-btn');
btn.addEventListener("click", () => {
table.classList.toggle("hide")
})
</script>
</body>
</html>

Javascript - Highlight a column name when clicking on it only

I have a html table (with column names: T1, T2, T3). I want to highlight a column name (T1) ONLY when it is clicked on by the user, the rest of the column names don’t have a highlight (T2, T3). Then when the user clicks on another column name (T2), it is highlighted, but I want all the other column names to be reset with no highlight (T1, T3).
How can I do it using only javascript, css, and/or html? Please dont include JQuery, I cannot use it.
var elems = document.querySelectorAll('td');
var fnClick = function(){
var ie = document.querySelectorAll('td');
for(var x = 0; x < ie.length; x++){
elems[x].classList.remove("red");
}
this.classList.add("red");
}
for (var i = 0; i < elems.length; i++){
elems[i].addEventListener("click", fnClick);
}
.red { background-color: red; }
<table>
<tr>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
<tr>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
<tr>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
</table>
When clicking, iterate through all column names and remove the class, lets say, "highlight".
After that add the class "highlight" to the column name clicked.
Or, look for elements by class name "highlight", and remove the class from all of them, then proceed to add the class to the clicked element.
First of all add an unique class to all the column elements for example- T1 for T1, T2 for T2, etc.
Then create a css class "highlight" with appropriate background color to create the highlight effect.
Then within the tags write an onclick function call like <td class="T1" onclick="addHighlight(T1)">...</td>
After that you can use JavaScript to create a function 'addHighlight' which is triggered when the user clicks on a column element. Within that function you can use getElemenstbyClassname to access the elements with class name of the column that was clicked(you passed in the class name use it as a parameter) and addClass method to add the class highlight.
To remove the highlight effect once another column is clicked just search for elements with the class "highlights" and use removeClass to remove that class and thus the highlight effect.
Refer to w3schools.com for further guidance. All is clearly explained there :)
You can do this by styling the :focus pseudo class for your td elements. In order to make your td element focus-able you would have to set the tabindex attribute to your td elements as well.
Index.html
<html>
<head>
<title>
Table Highlight
</title>
<style>
table {
border: solid;
}
td {
width: 100px;
height: 100px;
border: dotted 1px;
}
td:focus {
background-color: blue;
}
</style>
</head>
<body>
<table>
<tr>
<td tabindex="1">T1</td>
<td tabindex="1">T2</td>
<td tabindex="1">T2</td>
</tr>
<tr>
<td>10</td>
<td>11</td>
<td>12</td>
</tr>
<tr>
<td>20</td>
<td>21</td>
<td>22</td>
</tr>
</table>
</body>
</html>
Here is a codepen as POC:
https://codepen.io/anon/pen/eKMgvJ
If you want to highlight the corresponding column name (table head element) of the clicked table cell, then you would need to add a click handler on your table.

Why does JQuery show() function only work on one (rather than all) of elements with the selector?

JSFiddle.
In the following SSCCE, there is a <table> nested inside another <table>.
The question is about the click listener for #add button. Specifically, the last if/else block of the function. When you run this code, click the Add TextField button once (or more times), and you will see that the #remove button on which show() should be executed, is only shown for the first matched selector, and not both (or all) of them.
Ideally the Remove TextField should be shown for all the #remove selectors.
The question is why? How do I fix this?
$(document).on("click", "button#add", function() {
event.preventDefault();
var parentTable = $(this).parent().parent().parent().parent().parent().parent().parent().parent();
var lastTableRow = parentTable.children('tbody').children('tr:last');
//Adding the new row
parentTable.children('tbody').append(lastTableRow.clone());
//Reset lastRow variable
lastTableRow = parentTable.children('tbody').children('tr:last');
//Reset the fields
lastTableRow.find('table tbody tr td input').each(function() {
$(this).val('');
});
//update numberOfRows variable
var numberOfRows = parentTable.children('tbody').children('tr').length;
alert("numberOfRows:" + numberOfRows); //check
if (!(numberOfRows > 1)) {
$("#remove").hide();
} else {
$("#remove").show();
}
});
#outer-table {
padding: 20px;
border: 3px solid pink;
}
#inner-table {
border: 3px solid orange;
}
#remove {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="outer-table">
<tbody>
<tr>
<td>
<table id="inner-table">
<tbody>
<tr>
<td>
<p style="display:inline-block">Enter first complain:</p>
<input type="text" />
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button id="add">Add Textfield</button>
<button id="remove">Remove Textfield</button>
</td>
</tr>
</tfoot>
</table>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Table Footer</td>
</tr>
</tfoot>
</table>
That's because you're using id for a group of objects. id should be unique per document. You should use a class name instead.

Strikethrough Table and/or DIV

I currently utilized this method Linethrough/strikethrough a whole HTML table row and it works great.
However how do I attach it to a HTML check box onclick method?
http://jsfiddle.net/deaconf19/DrEhv/
<table border 1>
<tr>
<td>Status</td>
<td>Priority</td>
<td>Date</td>
<td>Event</td>
<td>Updated</td>
</tr>
<tr>
<td contenteditable/>Checkbox</td>
<td contenteditable/>3</td>
<td contenteditable/>02/07/2014</td>
<td contenteditable/>code needs updating again</td>
<td contenteditable/>02/07/2014</td>
</tr>
<tr class="strikeout">
<td contenteditable/>Checkbox</td>
<td contenteditable/>1</td>
<td contenteditable/>02/07/2014</td>
<td contenteditable/>code needs updating</td>
<td contenteditable/>02/07/2014</td>
</tr>
</table>
You can use jQuery, to find check box parents parent and add a class to it when status of checkbox changed
if ( this.checked) {
$(this).parent().parent().addClass("strikeout");
} else {
$(this).parent().parent().removeClass("strikeout");
}
Example
Just use javascript to change the table class. If using jQuery:
$('#myCheckbox').change(function(){
$('#myTableRow').toggleClass('strikeout', $(this).prop('checked'));
})
The text below assumes that you have a checkbox with id="myCheckbox" and a table row with id="myTableRow".
Why use jQuery if pure JS can do the same thing:
In your HTML, add onclick handler for checkboxes:
<input type="checkbox" onclick="strike(this)">
Then change class of TR element based on checkbox value, like this:
function strike(elm) {
if(elm.checked) {
elm.parentNode.parentNode.className = "strikeout";
} else {
elm.parentNode.parentNode.className = "";
}
}
As simple as that !

Categories