DataTable How to prevent row click in columns containing hyperlinks - javascript

I am dealing with a javascript datatable with clickable rows. Each row when clicked forwards the browser to a different page.
A column of the row contains a hyperlink. When the hyperlin is clicked I don't want the row click event to be fired or managed.
Here is how I have implemented the row click event
$(tableId+' tbody').on( 'click', 'tr', function (e) {
window.location.href = $(this).attr('url');
});

When you add an event listener to a parent, the event by default "bubbles" downwards and attaches the event to all children. So in this case you setting the event on tr (parent) and the event will bubble down and attach itself to the td (children). So one of these td from what I understand contains your href (hyperlink) and so to block the click event which originally was set on the parent, you have to set another event listener specifically of the event type click within the function for this event you simply need state event.stopPropagation() and it will override the tr click event which bubbled down.
document.addEventListener('DOMContentLoaded',()=>{
//SET EVENT ON PARENT(TR), EVENT BUBBLES BY DEFAULT DOWNWARDS THEREFORE TD's WILL INHERIT
document.getElementById('parent').addEventListener('click',()=>window.location.href = "wherever");
//ADDING ANOTHER EVENT LISTENER OF THE SAME TYPE (CLICK) WHICH BLOCKS THE BUBBLING PROPOGATION DOWNARDS
document.getElementById('myhyperlink').addEventListener('click',(e)=>event.stopPropagation());
});

If you want to prevent clicking on anchor from redirecting a page, you have to simply catch the click event and disable it's default behaviour.
$("table td a").click(function(e){
e.preventDefault();
});
You have to just prevent default behaviour, if you would also stop propagation of event, your other event listener wouldn't get called. See more info here: What's the difference between event.stopPropagation and event.preventDefault?
If your goal is to disable redirect of anchor links only when the javascript is enabled, another solution might be to set onclick attribute that would disable default redirect. However, this seems not to work in webkit based browsers.
and example
Here is jsFiddle with example

Use preventDefault()
$(tableId+' tbody').on( 'click', 'tr', function (e) {
e.preventDefault();
window.location.href = $(this).attr('url');
});

You can write code following ways:
$(tableId+' tbody').on( 'click', 'tr', function (e) {
e.preventDefault();
window.location.href = $(this).attr('url');
});

you have to disable row click for that particular column
$('tableId+' tbody'').on('click', 'td', function () {
if ($(this).index() == 4 ) { // provide index of your column in which you prevent row click here is column of 4 index
return;
}
// you can do additional functionality by clicking on this column here
});

Related

how prevent the parent click event on change a checkbox

I have a checkbox inside a parent container which has a click event, whenever I try to click the checkbox parent click works first and following by the change event, I am using e.stopPropagation(); on both the parent and child events, but still, it's not working
// make the .parent react
function grandParent(){
alert('Grand Parent: You hit me, my child or my grand child, now deal with me!');
}
// make the .parent react
$('.parent').on('click', function(e){
e.stopPropagation()
alert('Parent : Don\'t you dare hitting me or my child, again!');
});
// make the child cry, when we hit him.
$('.child').on('click', function(e){
e.stopPropagation();
alert('Child : waaaaaa waaaa waa huh huh waaa waaaa!');
});
$('.hello').on('change', function(e){
e.stopPropagation();
alert('checkbox clicked');
});
Fiddle example
You have to bind the click event on the checkbox and not the change event: http://jsfiddle.net/ohc8jt6w/
Sequence of the event matters , where the click event occurs first and Change event the next ,So in your case you need to change the type of event handling to Click click here to see the sequence / priority of events happening after clicking on check box
$('.hello').on('click change', function(e){
e.stopPropagation();
alert('checkbox '+e.type);
});
This happens because e.stopPropagation(); is on change event and .child has click event. You can do this like in #rikpg example, but if you need change event, you should just add new one click event to checkbox that only has stopPropagation
http://jsfiddle.net/wppv2152/2/

Stop events inside delegate with same handler

I have a table on which I use delegate on tr, each row also has a button. I need to perform some action on this button click. The click event on the button fires when it is clicked but it fires the number of times a user clicked anywhere else in the row plus the one time the button is clicked.
Here's a code snippet
JS
$('.detailTable').delegate('tr', 'click', function() {
console.log('clicked in row');
$('#saveButton').click(function(event) {
console.log('clicked on button');
return false;
});
});
HTML
<table class="detailTable">
<tr>
<td>first</td>
<td>
<button id="saveButton">
Save
</button>
</td>
</tr>
</table>
Working Fiddle
First of all, you didn't mention why you are using event delegation? As this isn't required if you are not creating/loading any new elements after page load via some code or using ajax.
The issue is you have a click event bound on the tr, which in turn binds an event on the button. So each time you click on tr it registers a new event so the callback is fired for each registration. If you click in the tr 3 times then for button the callback will be executed 3 times.
In my opinion you should just use normal click events.
You might do this:
$('.detailTable').delegate('tr', 'click', function() {
console.log('clicked in row');
}).delegate('#saveButton', 'click', function(e) {
console.log('clicked on button');
return false; // does two things e.preventDefault() & e.stopPropagation()
// and this will stop the event to bubble up to the tr element.
});
That is correct behaviour as you register a new handler for the button click each time you click on the row. Its not totally clear for me what you want to achieve.
To get the row from the button click event, you can try this:
$("#saveButton").click(function() {
var $item = $(this).closest("tr");
});
First off, you can't have multiple buttons with the same id. That's illegal HTML and will just cause problems for selectors. I'd suggest using a class name instead.
Then, you never want to be binding a new click handler every time something else is clicked. That just gets the click handlers piling up and you get multiple callbacks for each click handler you registered.
Then, unless you're using a really old version of jQuery, you should be using .on() instead of .delegate().
So, here's what I would suggest:
<table class="detailTable">
<tr>
<td>first</td>
<td>
<button class="saveButton">
Save
</button>
</td>
</tr>
<tr>
<td>first</td>
<td>
<button class="saveButton">
Save
</button>
</td>
</tr>
</table>
Code:
// save button click handlers
$('.detailTable').on('click', '.saveButton', function(e) {
// don't let button click handler propagate to the row
// you can remove this e.stopPropagation() line if you want
// a click to trigger both button and row click handlers
e.stopPropagation();
console.log('clicked on save Button');
});
// row click handlers
$('.detailTable').on('click', 'tr', function() {
console.log('clicked in row');
});
Working demo: https://jsfiddle.net/jfriend00/hy69py9m/
FYI, if you're not dynamically creating elements in this table, then there's no need for delegated event handling and you could just use static selectors to map your event handlers.
I don't really get what your question is but some remarks:
I've made this Fiddle with your code and some mild edits.
By delagating an event listener (the one with the button) inside another (the one with the row), there has to be first clicked on the row (or on the button, because it is in the row) only after that the event on the button will be listened to.
If you have multiple rows you have to make sure to not use the same id for every button. In the fiddle I have used a classname which solves that problem.
I suggest using two seperate listeners:
$('.detailTable tr').click(function() {
console.log('clicked in row');
});
$('.detailTable tr .saveButton').click(function(event) {
console.log('clicked on button');
event.stopPropagation();
});
the event.stopPropagation() (jQuery api) prevents the click to bubble up to the row so, when clicking on the button the row will not be clicked.

Preventing a JQuery click listener

I have a .click() on a div.
I added a button in the div and now every time I click the button, the JQuery does the function associated with the div and preforms the action on the button.
I understand why it is doing this. I was wondering if I could make the click listener ignore the children?
Is there already a function/syntax for that or do i need to make one from scratch? The div and the button are called by #id.
To make the event listener ignore children, you can check that the bound element is the same as the target
$('div').on('click', function(e) {
if ( e.target === this ) {
// DIV was clicked, not children
}
});
Or go the other way, preventing the event from bubbling up
$('div button').on('click', function(e) {
e.stopPropagation();
});

How to prioritize Nested JavaScript events?

I have an edit button inside a table cell.
The table cell event has an "click" event, And the edit button who is inside a cell has another click event set to it.
Is there a way to prioritize the button event over the table cell event?
I tried using a different z-index for the button, but it didn't work.
The button cannot go outside the the table as its closest tr holds id data which is crucial for the proper event to function.
You can call event.stopPropagation() as part of the click handler for the button, to prevent the click event from bubbling up to the table cell. Documentation: http://api.jquery.com/event.stopPropagation/
Inside the click handler on the button, you just need to call event.stopPropagation().
element.onclick= function(event) {
// ...
event.stopPropagation();
// ...
}
Look into a tutorial on bubbling and capturing events, such as http://javascript.info/tutorial/bubbling-and-capturing

jquery tablerow click function

I have a function that allows users to edit a row in a table by opening the data in a modal. Right now the whole row will fire the modal. What I want is to isolate the last td that contains a link that fires a function that readies the data for processing.
What happens is that when that last td is clicked the modal opens AND the ready function fires. I'm trying to stop the modal from opening.
I also have a mouseover row highlighting on each row of the table.
This is how I associate the table rows with the modal function:
$("#table").find("tr").click(function(e) {
//code to open model
}
This is how I fire the ready function:
$("#table tr td:last-child a").click(function(e) {
//code to open model
}
i believe you need to call e.stopPropogation() to prevent the event from propogating:
$("#table tr td:last-child a").click(function(e) {
//code to open model
e.stopPropagation();
return false;
}
Explanation:
Events propagate from the most "specific" element up to their parents. This is called bubbling, and in this case, your second modal is being fired because the click event is bubbling up from the A element to the TR element.
I believe all events propagate and bubble. Return false simply cancels the default action of the A element, which is to follow the link... it doesn't stop the event object.
Here's a good explanation of the whole thing.
Simply add "return false;":
$("#table tr td:last-child a").click(function(e) {
// whatever should happen when clicking the anchor
return false;
}
This prevents the event from propagating to the surrounding tr.
why instead of finding the link inside the last cell of any row in the table just assign a id or a class to your link
like ...
and then add the display : block property from the css which makes the anchor to fill the whole area it is contained in.
then simply
$('.anchorclass').click(function(){
// do something here
});

Categories