Link within a link onClick event - Avoid both click events triggering - javascript

I have a link within a link, both with an onClick event.
The outer link works as desired. However, the inner link triggers both onClick events. I would like it so that the outer event is not triggered when the inner link is clicked.
<div onClick="console.log(1)">
Inner
</div>
JSFiddle

Javascript events will propagate up through the tree.
So when you click on the inner anchor it will also emit any click events for elements higher up, so the div element.
To stop this the inner click handler has to prevent the event from propagating with e.stopPropagation();.
However this gets a little messy when you don't register handlers with .addEventListener() in JavaScript.
If you add events this way you can do it like this (first give your anchor an id, say inner) which is nice and easy:
document.getElementById('inner').addEventListener('click', function (e) {
e.stopPropagation();
console.log(2);
});
You can however pass the event into your click handler if you do wish to use the attribute, so:
Inner
//JS
function innerHandler(e) {
e.stopPropagation();
console.log(2);
}
Generally speaking (this is my opinion) i would avoid the latter. Events registered like this are difficult to remove and modify. You can't also easily register multiple handlers to the same element for the same event.
stopPropagation docs

Related

<a> tag only working on double click and not single click

Hi I have a <a> tag that is working on double click but not on single click.
I have a javascript function called on the tag.
Can someone help on same.
Below is the tag and the javascript function
function ShowPopup() {
$("#lnkAttachment").on("click", function () {
$('#divProjectAttachment').modal('toggle');
});
}
<a>href="javascript:void(0);" id="lnkAttachment" onclick="ShowPopup();">Click here to View Attachments!</a>
You're attaching event listener inside your ShowPopup function. Just update it to be like
function ShowPopup() {
$('#divProjectAttachment').modal('toggle');
}
And it will work fine.
Edit:
Why this happens?
Well, first of all, this works on 2nd click, not on double click.
Next,
You have attached onclick event handler in your <a></a> tag. Which triggers ShowPopup function.
And inside your ShowPopup function you're re attaching click event listener to the same element.
So first time when you click on your anchor tag, the ShowPopup will attach event listener to the #lnkAttachment. An important thing to note here is that that your ShowPopup function gets called on the first click. But it won't show you the popup because you're attaching the event listener to the element and that's it. Now the event listener is attached after the ShowPopup is called for the first time.
Next time when you click on the lnkAttachment the event listener is already present so it wil lshow the popup. Additionally, it will re-attach the click event listener again (and everytime the ShowPopup is called - which is unnecessary).
You can either keep your code as this answer demonstrates
OR
You can decide to follow good programming ethos and separate event attachment (JavaScript) from your display markup (HTML)
The way to do it is as follows.
Keep your anchor tag as
href="javascript:void(0);" id="lnkAttachment">Click here to View Attachments!
(Notice, no onclick event handler here)
and in your javascript you take care of event handling.
$(document).on('ready', function(){
$("#lnkAttachment").on("click", function () {
$('#divProjectAttachment').modal('toggle');
});
}
When you are using jQuery, you can wire up the events without onclick in html.
<a>href="javascript:void(0);" id="lnkAttachment">Click here to View Attachments!</a>
You can remove the onclick in markup and write your jQuery script in DOM ready.
$(function(){
$("#lnkAttachment").on("click", function () {
$('#divProjectAttachment').modal('toggle');
});
});

Catching click event while delete thumbnail

I slightly modified FU thumbnail template to hook a click event on it. I also display a delete button (the provided one).
The problem is that when I click on the delete button, the click event bubbles to the rest of the javascript stack.
How can I prevent the delete button to propagate the click event??
(usually you do something like event.stopPropagation()...).
Thanks for your help
If you'd like to prevent any DOM event from bubbling, simply attach an event handler to the element where you would like it to terminate and call stopPropagation() on the Event object. For example, for a click event:
someElement.addEventListener('click', function(event) {
event.stopPropagation();
});
The above code will not work in IE8 and older since addEventListener and stopPropagation were first introduced in IE9.

Need to get info from any element, which was clicked, but not from parent elements

Need to get info from any element, which was clicked.
Example:
<div>text1<section>text2</section></div>
and JS
$(function(){
$('body *').click(function(){
alert($(this).get(0).tagName.toLowerCase());
});
});
If I click text2, parent element throw alert too. I need only first alert from section. How I can block next alerts from all parent elements of section.
Use event.stopPropagation() to prevent the event from firing on the containing elements.
$(function(){
$('body *').click(function(e){
e.stopPropagation();
alert($(this).get(0).tagName.toLowerCase());
});
});
Just wanted to expand on Kooilnc answer - Using on with event delegation is another option.
Event delegation would be nice if you have an event listener bound before or after on a node that needs to listen to a click handler that has bubbled up. If you stopPropagation, this obviously would be an issue.
Here's a fiddle with a demo:
http://jsfiddle.net/ahgtLjbn/
Let's say a buddy of yours has bound an event listener to a node higher up in the DOM tree. He expects any events that bubble up to it, to be handled by his script.
Using event delegation, the event still bubbles up (so your buddies code will still fire), but it will only alert once (since we called e.stopPropagation).
Calling on without event delegation, or binding the event directly using click (which, under the hood, is just calling on) will prevent the event from bubbling, so your buddies code will never run.

JQuery selector still working after I remove the class?

I have two jquery functions that work together, one depends on a class, another removes the class.
Once it is removed I would expect the functionality to stop working, but it carries on?
Whats going on?
Here is the fiddle, try it out for yourself.
<div class="container disabled">
Go to Google
</div>
<label>
<input type="checkbox" />Enable link</label>
The JS
$('.disabled > a').click(function (e) {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
$('input[type=checkbox]').change(function () {
$('.container').removeClass('disabled');
});
It looks like you want to be using delegated event handlers rather than static event handlers. Let me explain.
When you run a line of code like this:
$('.disabled > a').click(function (e) {
this installs an event handler on any objects that match the selector at that moment in time. Those event handlers are then in place forever. They no longer look at what classes any elements have. So changing a class after you install a static event handler does not affect which elements have event handlers on them.
If you want dynanamic behavior where which elements respond to an event does depend upon what classes are present at any given moment, then you need to use delegated event handling.
With delegated event handling, you attach the event "permanently" to a parent and then the parent evaluates whether the child where the event originated matches the select each time the event fires. If the child no longer matches the select, then the event handler will not be triggered. If it does, then it will and you can add/remove a class to cause it to change behavior.
The general form of delegated event handlers are like this:
$("#staticParent").on("click", ".childSelector", fn);
You ideally want to select a parent that is as close to the child as possible, but is not dynamic itself. In your particular example, you don't show a parent other than the body object so you could use this:
$(document.body).on("click", ".disabled > a", function() {
e.preventDefault();
e.stopPropagation();
alert('should stop working');
});
This code will then respond dynamically when you add remove the disabled class. If the disabled class is present, the event handler will fire. If it is not present, the event handler will not fire.
Working demo: http://jsfiddle.net/jfriend00/pZeSA/
Other references on delegated event handling:
jQuery .live() vs .on() method for adding a click event after loading dynamic html
jQuery .on does not work but .live does
Should all jquery events be bound to $(document)?
JQuery Event Handlers - What's the "Best" method
jQuery selector doesn't update after dynamically adding new elements
Changing the class after the event handler is bound has absolutely no effect as the event handler is not suddenly unbound, it's still bound to the same element.
You have to check for the class inside the event handler
$('.container > a').click(function (e) {
if ( $(this).closest('.container').hasClass('disabled') ) {
e.preventDefault();
e.stopPropagation();
}
});
$('input[type=checkbox]').change(function () {
$('.container').toggleClass('disabled', !this.checked);
});
FIDDLE
When the selector runs, it gets a list of elements including the one in question and adds a click event handler to it.
Then you remove the class - so any subsequent jQuery selectors wouldn't get your element - but you have already attached the event so it will still fire.
The selector you have used runs on the line you declared it - it isn't lazily initialized when clicks happen.

jquery callback specificity

Is there any specificity associated with event callback with jQuery. Say, I register a mousedown event callback on a div element, and also on the document. Which one would trigger if I click on the div? Does the order of registration matters? or the specificity (like css) matters?
thanks.
It will bubble up the DOM tree and call all other events of that type.
You can stop this with event.stopPropagation().
Your example
If you assigned the events like so...
$(document).mousedown(function() { alert('document'); });
$('div').mousedown(function() { alert('div'); });
Mouse down anywhere will trigger document's handler, and get one alert dialog with document.
Mouse down on any div will trigger the div's handler, and then bubble up the DOM all the way to document where it will trigger its event handler. You will get two alert dialogs; first the div one and then the document one.
Both events will be triggered, first the div, and then the document click.
It will execute both, from inside out. Clicking in the div will fire the div event then the document. Example on jsFiddle
$(window.document).click(function(e){
alert("doc");
});
$("div").click(function(e){
alert("div");
});
You can avoid it firing other events with e.stopImmediatePropagation(). See this example
$(window.document).click(function(e){
alert("doc");
});
$("div").click(function(e){
alert("div");
e.stopImmediatePropagation(); // prevents $(doc) from rising
});

Categories