How to NOT select only specific elements in a table with jQuery? - javascript

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

Related

Whole table row clickable except the button with Javascript/jQuery

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>

HTML eventlistener on each row of 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>

Fire event once on DOM change

I'm using the following jQuery:
$('table').bind("DOMSubtreeModified",function(){
myfunction();
});
The contents of the table are modified by another function. However, this triggers the above for every element in the table that is changed.
Is there a way to fire only once after all table-changes have been made?
Use .one() to register once for an event. In this Snippet click the button to add a <td> to table, thereby triggering the DOMSubtreeModified event only once. Note any further modifications to table do not trigger anything.
SNIPPET
$('button').click(function() {
$('table tr').append('<td>TEST</td>');
});
$('table').one("DOMSubtreeModified", function() {
alert('MODIFIED');
});
table,
td {
border: 1px solid black;
}
table {
width: 300px;
height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td></td>
</tr>
</table>
<button>addTD</button>

Jquery Next() not highlighting next element correctly when using a table

I have a table with each row representing a song.
When a song is clicked, the parent td should be highlighted a light blue color with the .active class and if any song was highlighted previously the parent td's .active class should be removed.
This part works fine and is represented with this jquery:
$(".songs").click(function(){
$('.songs').parents('td').removeClass('active');
$(this).parents('td').addClass('active');
});
I also want to have a next button and a previous button. This where I am having issues. When the next button is clicked, the next song on the list should be highlighted and the previously highlighted song should be unhighlighted (I am using the class .active to do the highlighting and unhighlighting). This part is not working:
$('#next_button').click(function(){
var current = $('td.active');
$('.songs').parents('td').removeClass('active');
current.nextAll('td:first').addClass('active');
});
Here is the jsfiddle link:
jsfiddle Link
Here is my html code:
<table id="song_table">
<thead id="song_thead">
<tr>
<th id="table_head">Songs</th>
</tr>
</thead>
<tbody id="song_tbody">
<tr>
<td class="td_songs">
<a class="songs">
1
</a>
</td>
</tr>
<tr>
<td class="td_songs">
<a class="songs">
2
</a>
</td>
</tr>
</tbody>
</table>
<div id="next_button">
<p id="next_text">Next Button</p>
</div>
Here is my css:
.active{
background-color: #D9FAFA;
}
table{
text-align: center;
height: 100px;
width: 200px;
}
#table_head{
text-align: center;
}
#next_button{
height: 100px;
width: 200px;
background-color: lightgreen;
}
Here is my jquery
$(document).ready(function() {
$(".songs").click(function(){
$('.songs').parents('td').removeClass('active');
$(this).parents('td').addClass('active');
});
$('#next_button').click(function(){
var current = $('td.active');
$('.songs').parents('td').removeClass('active');
current.nextAll('td:first').addClass('active');
});
});
If you could help me solve this issue, I would greatly appreciate it. I feel like this should be so easy but I just can't seem to make it work.
Thanks!
The trick is to get the row index of the current song, add 1, and then do a modulo with number of rows that way if the current row+1 overflows the number of rows, it will start from the beginning:
$().ready(function() {
$(".songs").click(function(){
$('.songs').parents('td').removeClass('active');
$(this).parents('td').addClass('active');
});
$('#next_button').click(function(){
//here .parent() will get the current <tr>
//.parent().index() will get the index of the current <tr>
var currentID = $('td.active').parent().index();
//here .parent() will get the <tr>
//.parent().parent() will get the <tbody>
//.parent().parent().children() will get all the rows
//.parent().parent().children().length will get the row count
var nextID=(currentID+1)%($('td.active').parent().parent().children().length)
$('.songs').parents('td').removeClass('active');
$('td').eq(nextID).addClass('active');
});
});
.active{
background-color: #D9FAFA;
}
table{
text-align: center;
height: 100px;
width: 200px;
}
#table_head{
text-align: center;
}
#next_button{
height: 100px;
width: 2d00px;
background-color: lightgreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="song_table">
<thead id="song_thead">
<tr>
<th id="table_head">Songs</th>
</tr>
</thead>
<tbody id="song_tbody">
<tr>
<td class="td_songs">
<a class="songs">
1
</a>
</td>
</tr>
<tr>
<td class="td_songs">
<a class="songs">
2
</a>
</td>
</tr>
<tr>
<td class="td_songs">
<a class="songs">
3
</a>
</td>
</tr>
<tr>
<td class="td_songs">
<a class="songs">
4
</a>
</td>
</tr>
</tbody>
</table>
<div id="next_button">
<p id="next_text">Next Button</p>
</div>
Something like this? http://jsfiddle.net/y5ntap04/3/
You needed to go up the DOM and then where all the siblings are, you can go to the next() one.
Plus added a previous button for you.
$().ready(function () {
$(".songs").click(function () {
$('.songs').parents('td').removeClass('active');
$(this).parents('td').addClass('active');
});
$('#next_button').click(function () {
$('.songs').parents('td.active').removeClass('active').closest('tr').next().find('td').addClass('active');
});
$('#previous_button').click(function () {
$('.songs').parents('td.active').removeClass('active').closest('tr').prev().find('td').addClass('active');
});
});
in your code you have each td in its own tr meaning there is no next td to go to.
you should adjust your jquery to focus on the rows, as in this fiddle (shown below)
$().ready(function() {
$(".songs").click(function(){
$('.songs').parents('tr').removeClass('active');
$(this).parents('tr').addClass('active');
});
$('#next_button').click(function(){
var current = $('tr.active');
$('.songs').parents('tr').removeClass('active');
current.next('tr').addClass('active');
});
});
You'll also notice I'm using .next() which will just grab the next element or the next element which matches the argument (in this case tr) - no need to get all then restrict to just the first.
All this will make your fiddle behave as expected, however, if you want to target the td's within each of the tr's you'll have to add .find('td') to get the td out of the retrieved tr, like this. Here the only line that is changed is the one that adds the class on click of next, which is now: current.parent().next('tr').find('td').addClass('active');
Refactoring out $('.songs').parents('tr').removeClass('active'); into it's own function would also clear your code a bit and make it easier to follow, a good habit! (also +1 for using a variable to store a returned JQuery DOM object - var current = $('tr.active'); - another good habit for code clarity and efficiency, especially when you are deraling with more complicated DOM structures and functions)

How to make entire td a link?

How do I make this entire td a link?
<td id="blue-border"><span id="blue"></span></td>
Clicking td should make it behave like this (I know this is syntactically incorrect:
<td id="blue-border"><span id="blue"></span></td>
EDIT: so far all the suggestions are only making the span inside the td a link, help lol.
Use CSS.
td a { display: block; width: 100%; height: 100%; }
<table style="width: 100%">
<tr>
<td>Link</td>
</tr>
</table>
The CSS forces the link to expand to the full width and height of the TD.
You can't wrap a td in an anchor. Do this:
<td id="blue-border"> <span id="blue"></span></td>
Or
<td onclick="chooseStyle('green-theme', 360)" id="blue-border"><span id="blue"></span></td>
Add an anchor tag inside of the td and set its display attribute to block. This should make the entire td clickable.
#blue-border a{
display: block;
}
or
<a href="link" style="display:block;">
Define an OnClick event for the td:
<td id="blue-border" onclick="chooseStyle('blue-theme', 360)">...
If all you're doing is firing javascript, I'd suggest using onclick instead of an anchor tag in the first place, like:
<td id="cell123" onclick="chooseStyle('green-theme',360)">cell contents</td>
You can throw a simple css style on there if you want the mouse to become a pointer:
#cell123:hover { cursor: pointer; }
<table width="100%" class="blueCss">
<tr>
<td ID="tdBlue">
<span id="Blue">Hello</span>
</td>
<td>
<span>other col</span>
</td>
</tr>
</table>
css file:
.blueCss {
height: 100px;
width: 100px;
}
.blueCss td {
background-color: blue;
}
.blueCss:hover {
border-color: #00ae00;
}
.blueCss td:hover {
background-color: yellow;
cursor: pointer;
}
jQuery code:
$(document).ready(function(){
    var tdLink = $('#tdBlue');
    tdLink.click(function(){
         alert('blue-theme');
    });
});
Check here: jsFiddle.net
Use jquery with class
$("tr td.data_col").click(function() {
window.location = $(this).find('a').attr("href");
});

Categories