This is my first SO post, please let me know how to do better!
I have a function that clears the by setting the opacity to 0, it works, but it will make my file massive if if try to set up a whole spread sheet with each having the same function bar different ids,
Ideally, the way I want this to play out, is that clears itself, and will clear all blocks. And I want to do it without having to write duplicate functions.
Is it possible to have a function set over classes? I have tried with no success
Or is there a better way to run the JavaScript, like somehow onclick==clear.self ?
function Xf1() {
f1();
f2();
}
function f1() {
var element = document.getElementById("a1");
element.style.opacity = "0";
}
function f2() {
var element = document.getElementById("a2");
element.style.opacity = "0";
<tr>
<th onclick="Xf1()">Clear all</th>
</tr>
<tr>
<td onclick="f1()" id="a1"> text1</td>
<td onclick="f2()" id="a2"> text2</td>
</tr>
You can use event delegation
start by adding a class to the table element
add a class to the "clear all" heading
add a click event listener to the table element
If the click event target is a td element, set its opacity to 0.
If the click target is the clear all heading, set all td elements to opacity 0. You can do that by querying the table for td tags and then using forEach to change the opacity for each of them.
const myTable = document.body.querySelector(".my-table");
myTable.addEventListener("click", event => {
const target = event.target;
if (target.tagName == "TD") {
target.style.opacity = 0;
}
if (target.classList.contains("clear-all")) {
myTable.querySelectorAll("td").forEach(item => (item.style.opacity = 0));
}
});
<table class="my-table">
<thead>
<th class="clear-all">Clear all</th>
</thead>
<tbody>
<tr>
<td id="a1">text1</td>
<td id="a2">text2</td>
</tr>
</tbody>
</table>
set an id to parent tag then set onclick to that elements children.
if you set "container" as id you will have something like this:
var elements = document.getElementById("container");
for (let i = 0; i < elements.children.length; i++) {
elements.children[i].onclick = function () {
elements.children[i].style.opacity = "0";
};
}
Instead of adding onclick to each td element. Have it in table element. Like this
document.querySelector("#table").addEventListener("click", (event)=>{
if(event.target.dataset.type==='clear'){
const ids = ['a1', 'a2'];
ids.forEach((ele)=>{
document.querySelector(`#${ele}`).style.opacity = '0';
});
return;
}
event.target.style.opacity = "0";
}
)
<table id="table">
<tr>
<th data-type="clear">Clear all</th>
</tr>
<tr id="tableRows">
<td id="a1"> text1</td>
<td id="a2"> text2</td>
</tr>
</table>
Related
I was working on my react project and I put an onClick function and dataset to my <tr> element like this
<tr key={index} onClick={ev} data-ti={ddd.id} className={classs}>
and so in that ev function I tried to get the value from the dataset like this
function ev(e){
const {ti} = e.target.dataset
console.log(ti) // returns undefined
}
and instead of returning an id it returns undefined am I doing something wrong or maybe there's another way of doing it
It's likely that instead of clicking on the tr you're actually clicking on the td inside it. So you need to get the parentNode of that td first, and then grab the data attribute.
const tr = document.querySelector('tr');
tr.addEventListener('click', handleClick, false);
function handleClick(e) {
const { target: { parentNode } } = e;
const { dataset: { ti } } = parentNode;
console.log(ti);
}
<table>
<tbody>
<tr data-ti="test">
<td>Test</td>
</tr>
</tbody>
</table>
I'll add Rob's edit here.
const tr = document.querySelector('tr');
tr.addEventListener('click', handleClick, false);
function handleClick(e) {
const tr = e.target.closest('tr');
const ti = tr ? tr.dataset.ti : null;
console.log(ti);
}
<table>
<tbody>
<tr data-ti="test">
<td>Test</td>
</tr>
</tbody>
</table>
You can simply set the event inside your onClick with a variable of the value you want, like onClick={ev(ddd.id)}.
I have been given a table that has been created using the DOM and now I have to use if statements to print specific areas of that table. For example in the second photo, when i click 1 - 2 million, it should show the table but only display the countries that have a population that's between 1 and 2 million. My teacher has barely taught us JavaScript deeply and now gives us a DOM assignment that uses JavaScript If Statements. I would appreciate if someone could give an explanation on how i can print specific parts of the table when i click the links/button above. Thanks!
Here a roadmap:
Loop through your submenus with a for (or for ... in) statement and attach a click event listener on each one with addEventListener()
In the callback, this will refer to the <li> (or <a>, or whatever) element you clicked (and which is linked to an event). So you can access the DOM clicked element's data nor attributes.
In function of the clicked submenu, filter your <table> the way you want thanks to if statements. (even better: switch statement) Visually, rows will be hidden. In Javascript, you will update style attribute of the element.
Below an example. I propose to you to try to do it yourself with elements I gave you. Open the snippet if you are really lost.
Exemple:
Other functions/methods/statements I used below: querySelectorAll(), dataset, instanceof, parseInt(), onload, children
// Always interact with the DOM when it is fully loaded.
window.onload = () => {
// Gets all <button> with a "data-filter-case" attribute.
const buttons = document.querySelectorAll('button[data-filter-case]');
// For each <button>, attach a click event listener.
for (let i in buttons) {
const button = buttons[i];
// The last item of "buttons" is its length (number), so we have to check if
// it is a HTMLElement object.
if (button instanceof HTMLElement) {
button.addEventListener('click', filterTable); // Will execute the "filterTable" function on click.
}
}
}
// The function which will filter the table.
function filterTable(e) {
// Useless in my exemple, but if you have <a> instead of <button>,
// it will not execute its original behavior.
e.preventDefault();
// Get the value of "data-filter-case" attribute.
const filterCase = this.dataset.filterCase;
// Get all table body rows.
const tableRows = document.querySelectorAll('table > tbody > tr');
// Update display style of each row in function of the case.
for (let i in tableRows) {
const row = tableRows[i];
if (row instanceof HTMLElement) {
if (filterCase === 'more-than-44') {
if (parseInt(row.children[1].innerText) <= 44) {
// Hide the row.
row.style.display = 'none';
} else {
// Reset display style value.
row.style.display = '';
}
} else if (filterCase === 'less-than-27') {
if (parseInt(row.children[1].innerText) >= 27) {
row.style.display = 'none';
} else {
row.style.display = '';
}
} else if (filterCase === 'reset') {
row.style.display = '';
}
}
}
}
<button type="button" data-filter-case="more-than-44">More than 44</button>
<button type="button" data-filter-case="less-than-27">Less than 27</button>
<button type="button" data-filter-case="reset">Show all</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<td>45</td>
</tr>
<tr>
<th>2</th>
<td>50</td>
</tr>
<tr>
<th>3</th>
<td>24</td>
</tr>
</tbody>
</table>
I'm trying to understand why I can add certain items to a cell, such as 'id', and not other items such as an onclick. My goal is to have a button pressed, which adds a row to a table (which works) - and set some values on the that is generated/appended to the table. I've noticed that I can step into the console and do:
rows[row_#].cells[cell_#].id = 'foo';
and have it appear in the table on the and function; but the following will not appear on the :
rows[row_#].cells[cell_#].onclick = 'callEvent(this)';
Should I be assigning this differently?
<button type="button" id="btn_add_row" onclick="addRow()">Add Row</button>
<table class="table table-hover" id="sample_table">
<thead>
<th>Column A</th>
<th id='calculate'>Column B</th>
</thead>
<tbody>
<tr>
<td>Item 1</td>
//sample of the td I'd like the function to generate
<td id='calculate' onclick='callEvent(this)'>Item 2</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
// Code to add a row to the table and assign properties to new row
function addRow() {
var table = document.getElementById("sample_table");
var lastRow = table.length;
var numberOfCols = table.rows[0].cells.length;
var row = table.insertRow(lastRow);
for (var i=0;i<numberOfCols;i++) {
row.insertCell(i);
if (table.rows[0].cells[i].id === 'calculate') {
// The calculate id will appear on the TD after running
table.rows[i].id = 'calculate';
// The onclick event will not appear on the TD afer running
table.rows[i].onclick='callEvent(this)';
}
function callEvent(element) {
console.log('Calculate event fired!');
}
</script>
The biggest issue is that you are not supplying a callback function reference to your onclick property. You are supplying a string:
.onclick='callEvent(this)'
So, no function actually gets invoked when the click event occurs.
Next, you shouldn't be using event properties (like onclick) in your JavaScript or adding inline HTML event handling attributes at all (that technique is about 20 years old) as they:
Create "spaghetti code" that is difficult to read and debug.
Lead to duplication of code.
Don't scale well
Don't follow the separation of concerns development methodology.
Create anonymous global wrapper functions around your attribute values that alter the this binding in your callback functions.
Don't follow the W3C Event Standard.
Instead, do all your work in JavaScript and use .addEventListener() to set up event handlers.
Also (FYI) id attributes need to be unique, so when you create a new row or cell, don't reuse an already assigned id.
Here's an example:
// Place all of this inside of a <script> element that is just before the
// closing of the body (</body>)
// Get references to all elements that you'll be working with
var btnAddRow = document.getElementById("btn_add_row");
var tbl = document.getElementById("sample_table");
// Now, set up the event handling functions
btnAddRow.addEventListener("click", addRow);
// Code to add a row to the table and assign properties to new row
function addRow() {
var counter = 1; // id attributes must be unique. This will keep it that way.
var numberOfCols = tbl.rows[0].cells.length;
var row = tbl.insertRow();
for (var i = 0; i < numberOfCols; i++) {
var cell = row.insertCell(i);
cell.id = "row" + (tbl.rows.length - 1) + "cell" + counter;
// Now, we'll create a new button, place that button in the new cell and
// set up a click event handler for it.
var btn = document.createElement("button");
btn.textContent = cell.id;
btn.id = "btn" + tbl.rows.length + counter;
// Add a click event handler
btn.addEventListener("click", function(){
alert("You clicked cell: " + this.id);
});
// And now include the button in the cell
cell.appendChild(btn);
counter++; // Increment the counter after using it
}
}
td { border:1px solid black; }
td:nth-child(2) { cursor:pointer; }
<button type="button" id="btn_add_row">Add Row</button>
<table class="table table-hover" id="sample_table">
<thead>
<th>Column A</th>
<th id='calculate'>Column B</th>
</thead>
<tbody>
<tr>
<td>Item 1</td>
<!-- sample of the td I'd like the function to generate -->
<td id='calculate'>Item 2</td>
</tr>
</tbody>
</table>
Two things:
The onclick expects a function. So to solve your problem, change
table.rows[i].onclick='callEvent(this)';
to
table.rows[i].onclick=callEvent;
The second thing is, the parameter on an event is actually the event, and this refers to the element:
function callEvent(event) {
console.log('Calculate event fired!');
// "event" is the event
// "this" is the element
}
missing need to second bracket end and use this callEvent(this) without single inverted comma.
Like this...
<script type="text/javascript">
// Code to add a row to the table and assign properties to new row
function addRow() {
var table = document.getElementById("sample_table");
var lastRow = table.length;
var numberOfCols = table.rows[0].cells.length;
var row = table.insertRow(lastRow);
for (var i=0;i<numberOfCols;i++) {
row.insertCell(i);
if (table.rows[0].cells[i].id === 'calculate') {
// The calculate id will appear on the TD after running
table.rows[i].id = 'calculate';
// The onclick event will not appear on the TD afer running
table.rows[i].onclick=callEvent(this);
}
}
}
function callEvent(element) {
console.log('Calculate event fired!');
}
</script>
I am trying to click on each cell on the table so that the selected cells I click on change the background color from white to gray. I am also trying to make it like a toggle so if I click on the cell again the background changes from gray to white, but it is not doing anything. I found a similar question, but the answer was advanced coding. I want to create a simpler code. I checked Firebug, but I do not see any errors. I would appreciate any suggestions. I am new to Javascript.
http://jsfiddle.net/RE006/nyzswnx2/1/
HTML5:
<table class="bingo">
<tr>
<td id="square0"></td>
<td id="square1"></td>
<td id="square2"></td>
</tr>
<tr>
<td id="square3"></td>
<td id="square4"></td>
<td id="square5"></td>
</tr>
<tr>
<td id="square6"></td>
<td id="square7"></td>
<td id="square8"></td>
</tr>
</table>
JS:
var toggleHighlight = function () {
document.td.style.backgroundColor = "#cecece;"
}
window.onload = function () {
getElementsByTagName("td").onclick = toggleHighlight ();
}
First of all: document.getElementsByTagName('td') returns a NodeList and not a single node, so you have to cycle on it to attach the event listener:
JS:
window.onload = function () {
var tds = document.getElementsByTagName("td");
for (var i = 0; i < tds.length; i++)
tds[i].onclick = toggleHighlight;
}
Please note that in the row tds[i].onclick = toggleHighlight;, toggleHighlight doesn't have ( and ) because it is a reference to a function and not a call to a function.
If you want to do things the web dev way, you should use classes instead of setting the color explicitly, so you can have:
JS:
function toggleHighlight() {
var td = this;
if (td.className == 'highlight')
td.className = '';
else
td.className = 'highlight';
}
CSS:
.highlight {
background-color: #cecece;
}
You can see the working example here: http://jsfiddle.net/nyzswnx2/40/
Please note that in order to make window.onload work I selected No wrap - in <body> instead of onLoad in the top left dropdown.
Note that
document.getElementsByTagName returns an array.
when you set onclick, you're going to need a function (function() {}), not the return value of that function (which is undefined in your example of onclick = toggleHighlight ();)
As per your JavaScript, you might want to try something like
var toggleHighlight = function (e) {
var bg = e.target.style.backgroundColor;
if (bg == 'red') {
e.target.style.backgroundColor = '';
} else {
e.target.style.backgroundColor = 'red';
}
}
var prepareTable = function () {
var cells = document.getElementsByTagName("td");
for (var i = 0 ; i < cells.length ; i++) {
cells[i].onclick = function(event) {
toggleHighlight(event);
}
}
}
document.onload = prepareTable();
Fiddle: http://jsfiddle.net/nyzswnx2/47/
you can use jQuery it's more simple.
add a class css :
.gray {
background-color:#efefef;
}
and change your code js with :
$(document).ready(function(){
$('td').on('click',function(){
$(this).toggleClass('gray');
});
});
Demo :
http://jsfiddle.net/nyzswnx2/51/
getElementsByTagName("td").onclick = toggleHighlight ();
First, this line is wrong, since getElementsByTagName() returns a list one is in need for a loop.
var tL = getElementsByTagName("td");
for(var i=0, j=tL.length; i<j; i++) tL[i].onclick = function(){this.style.backgroundColor = "#cecece"}
There is another possibility. Instead of defining an onclick() event for each cell in the table one could use onclick() event on the table and later on use the function document.elementFromPoint() to get the td. Yet the way used in the post (onclick() event on td) is pretty much standard.
To toggle the colors one needs to check whether colors are set yet or not (cecece in this case).
Example
<html>
<head>
<script>
function Init(){
document.querySelector('table').onclick = function(event){colorCell(event)}
}
function colorCell(event){
var tE = document.elementFromPoint(event.clientX, event.clientY);
if (tE.tagName === 'TD') tE.style.backgroundColor = (tE.style.backgroundColor === '') ? '#cecece' : ''
}
</script>
</head>
<body onload = 'Init()'>
<table>
<tr>
<td>0.0</td>
<td>0.1</td>
<td>0.2</td>
</tr>
<tr>
<td>1.0</td>
<td>1.1</td>
<td>1.2</td>
</tr>
<tr>
<td>1.0</td>
<td>1.1</td>
<td>1.2</td>
</tr>
</table>
</body>
</html>
First things first: your fiddle is already set to run the code on window.onload, so you have no need to repeat it. You can just write the code and it will automatically be executed upon load.
Now, for your question: you are attempting to assign an event listener to a Node Collection, while you really want to assign the event listener to each element of said collection. There are many ways to go about it, but you can safely do it like this:
var cells = document.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
cells[i].addEventListener('click', toggleHighlight);
}
Please note two things:
I've used addEventListener instead of assigning the function to the onclick event. I encourage you to look up both ways of assigning events.
When assigning a function to an event or, generally speaking, referring to a function as a variable, you should NOT call the function, but simply refer to it by its name. In this example, I have passed the toggleHighlight function to the addEventListener function as its second parameter just by passing it the name of the function, not by calling it. If you were to call the function, the second parameter passed to the addEventListener function would be the return value of the toggleHighlight function, not a reference to the function itself. I encourage you to look up the differences between calling a function in JavaScript and passing a function as a reference.
Let's take a look to the toggleHighlight function now: this function is somehow special, because it responds to an event. As such, its first parameter is a reference to an event itself, and the function should therefore be written like this:
function toggleHighlight(event) {
var cell = event.target;
cell.style.backgroundColor = '#cecece';
}
See what I did there? I used the event object to get the target of the event, and I've set the style on the target itself. Every time a cell is clicked, the target of the event will refer to the cell on which the event was triggered.
Toggling the color requires your code to be stateful: it must somehow save the state of each cell, and use it to decide which color should be used for the background of the cell. Sure, we could use the color of the cell as a state, but that's not really acceptable so we're going to do some more work to get things working. The first thing you want to do is define the states that will be available, and store the initial state of each cell somewhere. We could updated our code like so:
const SQUARE_OFF = 0;
const SQUARE_ON = 1;
var cells = document.getElementsByTagName('td');
var cellStates = {};
for (var i = 0; i < cells.length; i++) {
cells[i].addEventListener('click', toggleHighlight);
cellStates[cells[i].id] = SQUARE_OFF;
}
Let's look at what I did:
I declared two constants, one for each state, and assigned an arbitrary value to each of them. This is NOT the only way to do it, it's just one way;
I declared the cellStates variable as an empty object. We'll use this to store the states of each cell;
While looping through the cells, I used the current cell's id as the key to be used to store the cell's state within the cellStates object. Initially, all cells are going to be off. At the end of the loop, your cellStates will have a key for each cell with the cell's state stored within.
Now that we have saved the state, we want to update it every time we click on a cell, and change the color of the cell accordingly. Let's update our toggleHighlight function:
function toggleHighlight(event) {
var cell = event.target;
var cellState = (cellStates[cell.id] === SQUARE_OFF) ? SQUARE_ON : SQUARE_OFF;
cellStates[cell.id] = cellState;
cell.style.backgroundColor = (cellState === SQUARE_OFF) ? '#fff' : '#cecece';
}
And, just like that, you can now toggle the color of each cell upon clicking. I encourage you to experiment and understand what's going on here very carefully before moving on to other topics. Have fun and happy learning!
Complete fiddle: http://jsfiddle.net/nyzswnx2/29/
I like to delegate
Vanilla JS
window.addEventListener('load', function(e) {
document.getElementById('tb').addEventListener('click', function(e) {
const tgt = e.target.closest('td');
if (tgt) tgt.classList.toggle('selected')
})
})
table,
th,
td {
border: 1px solid #000;
border-collapse: collapse;
font-size: 1.0rem;
margin: 25px auto 0px auto;
text-align: center;
}
th,
td {
padding: 5px 10px;
}
/* bingo table */
.bingo td {
color: #000;
padding: 20px;
}
.bingo .selected {
background-color: red;
}
<table class="bingo">
<tbody id="tb">
<tr>
<td id="square0"></td>
<td id="square1"></td>
<td id="square2"></td>
</tr>
<tr>
<td id="square3"></td>
<td id="square4"></td>
<td id="square5"></td>
</tr>
<tr>
<td id="square6"></td>
<td id="square7"></td>
<td id="square8"></td>
</tr>
<tbody>
</table>
jQuery
$(function() {
$('#tb tbody').on('click', 'td', function(e) {
$(this).toggleClass('selected')
})
})
table,
th,
td {
border: 1px solid #000;
border-collapse: collapse;
font-size: 1.0rem;
margin: 25px auto 0px auto;
text-align: center;
}
th,
td {
padding: 5px 10px;
}
/* bingo table */
.bingo td {
color: #000;
padding: 20px;
}
.bingo .selected {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<table class="bingo" id="tb">
<tbody>
<tr>
<td id="square0"></td>
<td id="square1"></td>
<td id="square2"></td>
</tr>
<tr>
<td id="square3"></td>
<td id="square4"></td>
<td id="square5"></td>
</tr>
<tr>
<td id="square6"></td>
<td id="square7"></td>
<td id="square8"></td>
</tr>
<tbody>
</table>
I have a Datatable in asp.net that i want to modifiy. I select the <tr> rows of the Datatable with JQuery:
var rows = $("#dgInformation tr:gt(0)");
However, the <tr>elements have multiple <td>elements and some of them are marked as display:none. How can i get the rows-variable without those hidden cells?
The purpose of this is to check cells if they are different from each other and only one line for each difference should be displayed. If i dont filter the not displayed elements, they get also compared and i have lines, which are visually the same.
Update
It works with just adding a CSS class to the <td>-elements that should be hidden. Then you have a clean DOM-Tree (i hope i can call it this way) in Firebug. The whole function below for reference:
function filterTable()
{
var rows = $("#dgInformation tr:gt(0)");
var prevRow = null;
var counter = 2;
rows.each(function (index) {
if (prevRow !== null) {
var i = 1;
var changes = 0;
$(this).children("td:visible").each(function () {
if(i > 2){
if ($(':nth-child(' + i + ')', $(prevRow)).html() != $(this).html())
{
$(':nth-child(' + i + ')', $(prevRow)).css('backgroundColor', '#00FF00');
changes = changes + 1;
}
}
i++;
});
if(changes == 0)
{
$(prevRow).css('display','none');
$(prevRow).removeClass();
}
else
{
$(prevRow).removeClass();
if(counter % 2 == 0)
$(prevRow).addClass('dgItemStyle');
else
$(prevRow).addClass('dgAlternatingItemStyle');
counter = counter + 1;
}
}
prevRow = this;
});
}
You can use the :not() filter for this.
If you have html like
<table id='tableid'>
<tr><td></td>
<td class="hidden">Hidden Cell</td>
<td>3</td>
<td>4</td></tr>
<tr>
<td>5</td>
<td class="hidden">Hidden Cell</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>8</td>
<td class="hidden">Hidden Cell</td>
<td>9</td>
<td>1</td>
</tr>
</table>
CSS:
.hidden{
display:none;
}
Script:
If u want all the td elements in that table without hidden td elements then,
var rows = $("#dgInformation tr:gt(0) td:not('.hidden')");
It would work!!
Try this:
var rows = $("#dgInformation tr:gt(0)").find('td').not(':visible').remove();
I see you're using jQuery.. So would
var rows = $("#dgInformation tr:gt(0)").not($("#dgInformation tr:gt(0)").has("td[display=none]"));
work?
Since you only want the td's that are visible, the following should suffice:
var visible_cells = $("#dgInformation tr:gt(0)").find("td:visible");
If you want the ones that are not visible, use :hidden instead :)
Update
I'm not sure what you mean by "How can i get the rows-variable without those hidden cells?".
If I read that correctly, you basically want the row, and have it's non-visible cells removed from the variable but kept in HTML.
This can't be done, as the variable you hold is still based on the actual HTML. The row-variable will not even contain any of the children. They will be looked up in the DOM when you request them specifically.
However, I assume at some later stage in your code, you actually get the selected row's <td> children. Apply the :visible filter on them whenever you need them, or make a second variable which holds the children you want, like I suggested in my answer.
You just can't pre-emptively delete them from a variable without altering the HTML.