I don't understand this js code here in this example. This code is to highlight a cell on click. Instead of assigning an onclick handler to each (can be many) – we’ll setup the “catch-all” handler on element. It will use event.target to get the clicked element and highlight it. But I don't understant the js part here. I want detailed explanation for it and if there any other method to do the same thing.
let table = document.getElementById('bagua-table');
let selectedTd;
table.onclick = function(event) {
let target = event.target;
while (target != this) {
if (target.tagName == 'TD') {
highlight(target);
return;
}
target = target.parentNode;
}
}
function highlight(node) {
if (selectedTd) {
selectedTd.classList.remove('highlight');
}
selectedTd = node;
selectedTd.classList.add('highlight');
}
#bagua-table td {
width: 150px;
text-align: center;
padding-top: 5px;
padding-bottom: 12px;
background-color:#000;
color: #fff;
}
#bagua-table .highlight {
background: red;
}
<table id="bagua-table">
<tr>
<td class="nw"><strong>Northwest</strong></td>
<td class="n"><strong>North</strong></td>
<td class="ne"><strong>Northeast</strong></td>
</tr>
<tr>
<td class="w"><strong>West</strong></td>
<td class="c"><strong>Center</strong></td>
<td class="e"><strong>East</strong></td>
</tr>
<tr>
<td class="sw"><strong>Southwest</strong></td>
<td class="s"><strong>South</strong></td>
<td class="se"><strong>Southeast</strong></td>
</tr>
</table>
What the code is doing is handling the event at the <table>. When a user clicks any one of the cells an event is generated and bubbles up to parent elements. The initial target in this case is the cell that was clicked and the if (target.tagName == 'TD') code block is triggered. This in turn calls the highlight function to set the new highlighted cell by removing the .highlight class from last highlighted cell and add it to the currently targeted one.
In order to be more robust, the code doesn't make an assumption about what element generates the event, because the <td> cells can also contain other html tags. This is why it needs to have the while (target != this) loop. The original target might not be a <td> tag but one of it's ancestors will be.
Related
I have a simple table and I write some JS code in order to achieve that whole tr become a data-href. Everything works very nice except for one thing.
Now the whole row is clickable and that is fine, but there is a small issue, if you click on the delete button, it takes you to the update page (data-href), and I want to avoid that. So my question is how can I modify that code for the whole row to stay clickable except that delete button?
Here is my code:
$("tr").each(function() {
const $tr = $(this);
$tr.attr("data-href", $tr.find("a").attr("href"))
})
$('*[data-href]').on('click', function() {
window.location = $(this).data("href");
});
.modal {
padding:5px;
background-color:red;
color:#fff;
cursor: pointer
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<table>
<tr>
<td>Name</td>
<td> Age</td>
<td>
Update
<a data-toggle="modal" class="modal" data-target="#deleteModal">Delete</a>
</td>
</tr>
</table>
Can somebody try to help me with this?
To achieve this you can use the is() method to determine what element within the tr was clicked on. If it was an a element then you can prevent the window.location from being updated.
Also note that you can update the data-href of each tr using an implicit loop which makes the code slightly more succinct. Try this:
$('tr').attr('data-href', function() {
return $(this).find('a').attr('href');
});
$('*[data-href]').on('click', function(e) {
if (!$(e.target).is('a')) {
window.location.assign($(this).data("href"));
}
});
.modal {
padding: 5px;
background-color: red;
color: #fff;
cursor: pointer
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<table>
<tr>
<td>Name</td>
<td>Age</td>
<td>
Update
<a data-toggle="modal" class="modal" data-target="#deleteModal">Delete</a>
</td>
</tr>
</table>
Here is the problem:
I have a table with rows that have keypress listeners
Each row is contentEditable
I want to make the wrapping tbody element contentEditable (to allow selecting multiple rows by click and dragging)
If I do make tbody contentEditable the keypress event is no longer
triggered in the rows
only the tbody element recieves the event
The main issue is that setting tbody as editable obscures the keypress events for the table rows
EDIT:
Is there any form of pointer-events:none for keyboard events?
How can I have the rows still recieve the event or how can I enable drag and select without making tbody/table contentEditable?
Would appreciate any feedback or help, thanks!
Here is an example code snippet if the description is unclear:
<style>
table{
background-color: cyan;
}
table, th,td, tr{
border: 1px solid black;
border-collapse: collapse;
}
tr,td, th {
padding: 3px;
text-align: left;
height: 2em;
}
</style>
<div>
<table>
<thead style = "background-color:white">
<tr>
<th>Value</th>
</tr>
</thead>
<tbody> <!-- need to make this tbody contenteditable -->
<tr contenteditable = 'true' onkeypress='keyPressed(event)'>
<td>v1</td>
</tr>
<tr contenteditable = 'true' onkeypress='keyPressed(event)'>
<td>v2</td>
</tr>
</tbody>
</table>
</div>
<script>
function keyPressed(){
if(event.keyCode == 13){
event.preventDefault();
row = event.target;
row.insertAdjacentHTML('afterend',"<tr contenteditable = 'true' onkeypress='keyPressed(event)'><td></td></tr>");
row.nextSibling.focus();
}
}
</script>
document.querySelectorAll('contenteditable td')
.forEach(e => e.addEventListener("click", function() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}));
lear more.
You can use element.target to see which element is actually being click on. For example, in my snippet tbody and the tr has contenteditable but as you can see in the console, element.target and element.currentTarget both retrieve a different field so you know you can use it that way.
But I would probably just recommend using divs instead, as they will be easier to work with.
document.querySelector('[contenteditable]').addEventListener("click", function(el) {
console.log(el.target,el.currentTarget)
});
/*
function keyPressed() {
if (event.keyCode == 13) {
event.preventDefault();
row = event.target;
row.insertAdjacentHTML('afterend', "<tr contenteditable = 'true' onkeypress='keyPressed(event)'><td></td></tr>");
row.nextSibling.focus();
}
}*/
table {
background-color: cyan;
}
table,
th,
td,
tr {
border: 1px solid black;
border-collapse: collapse;
}
tr,
td,
th {
padding: 3px;
text-align: left;
height: 2em;
}
<div>
<table>
<thead style="background-color:white">
<tr>
<th>Value</th>
</tr>
</thead>
<tbody contenteditable='true'>
<!-- need to make this tbody contenteditable -->
<tr contenteditable='true'>
<td>v1</td>
</tr>
<tr contenteditable='true'>
<td>v2</td>
</tr>
</tbody>
</table>
</div>
In function ClickedRow, i want to use the "a" which is being clicked. So i want to receive it as a parameter.
<td ...... >
<span class="......>
<span onmousedown="event.cancelBubble = true">
<a class="GridLinkRenderer" href="javascript:ClickedRow(this)" onclicklink="javascript:ClickedRow(this)" urlText="XXXX">
<td ......
<span class="......>
<span onmousedown="event.cancelBubble = true">
<a class="GridLinkRenderer" href="javascript:ClickedRow(this)" onclicklink="javascript:ClickedRow(this)" urlText="XXXXX">
Based on clicked <a ....> I would like to hide/show it (or to show/hide next <a class= "GridLinkRenderer" in other <td ...>) by function ClickedRow(this).
How can I do it ?
I've tried to send the clicked $(row).next().eq(0).tagName and row.style.display = 'none' , it says that it is "undefined".
function ClickedRow(row){
$(row).next().eq(0).hide();
$(row).hide();
}
Instead of this, remove href and use
$('#TheidOfTheA').on('click'function(){
let myAElement = $(this);
}
have you looked at closest(),find() and next() ?
https://api.jquery.com/closest/
https://api.jquery.com/next/
https://api.jquery.com/find/
$(row).closest('td').next('td').find('.GridLinkRenderer')
haven't tested this.. but if I'm thinking right this should be at least the point to right direction.
I can't tell by OP if the td are being used in a tr and the tr in a table as it should so I'll just mention real quick that it's invalid HTML should there be any td without a tr as a parent and it's invalid HTML having a tr without a table as its ancestor.
If starting at a tag nested within a td you'll need to climb out:
$(this).closest('td')...
Once at the cell level look around for the cells to the left: ....prev('td'), or to the right: ....next('td') or both: ....siblings('td'). Then go down each td and find the link nested within and turn it off/on: ....find('.gLR').fadeToggle();
$(this).closest('td').siblings('td').find('.gLR').fadeToggle();
$('.gLR').not('.g5').hide();
$('.gLR').on('click', function(e) {
if ($(this).hasClass('g5')) {
$('.gDir').fadeToggle();
} else if ($(this).hasClass('g1') || $(this).hasClass('g9')) {
const cell = $(this).closest('td');
cell.siblings('td').find('.gLR').fadeToggle();
} else if ($(this).hasClass('g4')) {
$(this).closest('td').prev('td').find('.gLR').fadeToggle();
} else if ($(this).hasClass('g6')) {
$(this).closest('td').next('td').find('.gLR').fadeToggle();
} else {
return false;
}
});
:root {
font: 700 5vw/1.5 Consolas
}
table {
table-layout: fixed;
border-collapse: collapse;
}
td {
width: 20%;
text-align: center
}
a {
display: block;
height: 10vh;
text-decoration: none;
color: cyan;
}
a:hover {
color: tomato;
}
a.g5:hover {
font-size: 0;
}
a.g5:hover::after {
content: '\1f536';
font-size: 5vw;
}
td b {
display: block;
height: 10vh;
}
<table>
<tr class='gRA'>
<td colspan='2'>
<b>🌈</b>
</td>
<td><b>⮝</b></td>
<td colspan='2'>
<b>🦄</b>
</td>
</tr>
<tr class='gRB'>
<td><b>🏰</b></td>
<td><b>⮜</b></td>
<td><b>🔷</b></td>
<td><b>⮞</b></td>
<td><b>🏯</b></td>
</tr>
<tr class='gRC'>
<td colspan='2'>
<b>🔥</b>
</td>
<td><b>⮟</b></td>
<td colspan='2'>
<b>💀</b>
</td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I tried both recommendations(thx for it) - no success.
It looks that the "this" argument is not passed like clicked element(object) reference.
The parameter "row" seems to be like parent of all object, so like new Object and not the clicked object.
I am not sure if href="javascript:ClickedRow(this)" onclicklink="javascript:ClickedRow(this)" is correct syntax though.
so copied Your sample and came up with this. ;) try this out.. and
make sure You understand what's happening here.
$(() => {
$("body").on("click",".GridLinkRenderer", (e) => {
e.preventDefault();
//works on the first link.. stil misses a few check..
//for example do we have the next td.. at all..
console.log($(e.currentTarget).closest('td').next('td').find('.GridLinkRenderer'));
})
});
So I made a 5x5 grid using HTML's <table> element. I want each cell to turn red when it is clicked and revert back to white when it isn't. It looks like it won't detect the first ever click on each cell. Once the first click has been triggered, it alternates from red and white normally under 1 click, but when you click it for the very first time for that instance, it does not respond. Why is it that a cell responds on the first click after it has been clicked on twice, but doesn't respond on the first click if it has never been touched before?
HTML snippet:
<div class="board">
<table type="board">
<tr>
<td id="r1-c1" onclick="changeColor('r1-c1')"></td>
<td id="r1-c2" onclick="changeColor('r1-c2')"></td>
<td id="r1-c3" onclick="changeColor('r1-c3')"></td>
<td id="r1-c4" onclick="changeColor('r1-c4')"></td>
<td id="r1-c5" onclick="changeColor('r1-c5')"></td>
</tr>
...
</table>
</div>
<button id="submit" onclick="submitted()">Generate</button>
The snippet is nested inside body and 2 div tags respectively.
CSS snippet:
table[type=board],tr,td{
background-color: white;
min-width: 80px;
min-height: 380px;
border: 2px solid black;
text-align: center;
font-size: 25px;
margin: 0px;
}
JS code:
function changeColor(id)
{
if(document.getElementById(id).style.backgroundColor == "white"){
document.getElementById(id).style.backgroundColor = "red";
}else{
document.getElementById(id).style.backgroundColor = "white";
}
}
Use the following code. It will work.
function changeColor(id){
if( (document.getElementById(id).style.backgroundColor == "white") || (document.getElementById(id).style.backgroundColor == "")){
document.getElementById(id).style.backgroundColor = "red";
}else{
document.getElementById(id).style.backgroundColor = "white";
}
}
You have not provided the HTML, So I have to create the DOM.
document.getElementById(id).style.backgroundColor
Do you mean to say each of the cell has an id?
Which may be too complex for large grid. Instead you should use rowIndex & cellIndex to locate a particular cell.
Also you can use event object and find the target. Saying that it mean event.target will help you to locate the cell which is clicked
var getTable = document.getElementById("demoTable");
//Declare a variable to hold the cellIndex & rowIndex
// On next click check if this values,& if not null change the background color of that cell
var col = "";
var row = "";
getTable.addEventListener('click',function(event){
console.log(col,row)
if(col !== "" && row !== "" ){
document.getElementById('demoTable').rows[row].cells[col].style.backgroundColor ="transparent" ;
}
col = event.target.cellIndex;
row = event.target.parentNode.rowIndex;
//Set background of the cell on which it is clicked
document.getElementById('demoTable').rows[row].cells[col].style.backgroundColor ="red" ;
})
JSFIDDLE
I have this fiddle: http://jsfiddle.net/v9s5ezpb/1/
HTML
<table>
<tr>
<td>test1</td>
<td>test2</td>
<td>test3</td>
<td>test4</td>
<td>test5</td>
<td class="no-alert">test6</td>
</tr>
</table>
CSS
table {
border: 1px solid #000;
}
table td {
border: 1px solid #000;
padding: 10px;
}
JS
$(document).on('click', 'table td:not(.no-alert, a)', function()
{
alert(1);
});
I want my code to execute an alert window on each time I click on any of the table TD items, except those items that have a specific class or has an anchor tag.
How is that possible?
A <td> can't be an <a> but it can have descendant <a> for which you could use :has() selector.
$(document).on('click', 'table td:not(.no-alert, :has(a))', function()...
EDIT: Update allowing click on <td> with <a> but not when <a> is target
$(document).on('click', 'table td:not(.no-alert)', function(event){
if(!$(event.target).closest('a').length ){
// is not click on <a>` tag
}
});
Used closest() to check target in case <a> has any children like <i> or <img> that could potentially be the actual target
DEMO