How do I trigger click on a child element without letting the click event bubble upto the parent & thereby create a infinite trigger loop of click event.
For example I have like this:
<li>
<a> ... </a>
</li>
I want to trigger a click event on a whenever li is clicked, but to prevent infinite trigger loop, I should avoid event propagation upto parent. How do I do that ?
Something like this?
$('li').on('click','a', function(e) {
e.stopPropagation();
// your code here...
});
By using .stopPropagation() on the anchor you can stop the bubbling. You should be able to use something like:
$('a').click(function (e) {
e.stopPropagation();
console.log('link');
});
$('li').click(function () {
$('a').click();
});
jsFiddle example
You do not state exactly the behavior you want from the click on the link, but if you simply want to stop the click being handled at all, use preventDefault() on the event argument of click:
$('li').on('click','a', function(e) {
e.preventDefault();
});
If you just want to stop the parent seeing the event use stopPropagation() instead:
$('li').on('click','a', function(e) {
e.stopPropagation();
});
The other option is return false, which does the same as both preventDefault() and stopPropagation()
$('li').on('click','a', function(e) {
return false;
});
use event.stopPropagation()() in the event callback.
$('selector').click(function(event){
event.stopPropagation()();
})
Parse the tag name on the parent click handler. (You could also look at class name or ID, among other event filters.) If desirable child tag is detected, then stop the propagation and return true so that this event runs. If desirable child tag is not detected, then prevent default event and return false. Thus, clicking on LI will trigger the click on A without a runaway event loop, and clicking on A will proceed properly without a runaway event loop either. Note also that you can't just fire the .click() event on the tag. You need to send it deeper into the native DOM element, using [0].click(), as I have shown below.
$('LI').click(function(e){
var sTag = e.target.tagName.toUpperCase();
if (sTag == 'A') {
console.log('DEBUG: A click');
e.stopImmediatePropagation();
return true;
} else {
console.log('DEBUG: ' + sTag + ' click');
e.preventDefault();
// the following won't work without the [0]
$(this).find('A')[0].click();
return false;
});
Related
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/
How can I listen to a change event on a checkbox without triggering a click event on its container?
<label><input type="checkbox"> Hello world</label>
I want to trigger an action on the checkbox's change event, but I don't want it to bubble up to a click event on the label.
(function ($) {
$('input').change(function (v) {
v.stopPropagation();
});
$('label').click(function () {
alert('You should not see this message if you click the checkbox itself!');
});
})(jQuery);
http://jsfiddle.net/r49PA/
Any ideas? Thanks!
The issue is that two events are triggered when you click the checkbox -- a change and a click. You're only catching the change, so the click isn't ever being told to stop propagation. You need to either add a second handler on the checkbox for click events, or combine one handler to catch both types, like this:
$('input').on('change, click', function (v) {
v.stopPropagation();
});
Here's a jsFiddle demonstrating a combined handler: http://jsfiddle.net/r49PA/4/
You can stop propagation on click event instead of change event since you bind click event for the parent label:
$('input').click(function (v) {
v.stopPropagation();
});
Updated Fiddle
With plain javascript you can do something like this:
var stopPropagation = false;
selector.addEventListener('mousedown', function(event) {
// simulating hold event
setTimeout(function() {
stopPropagation = true;
// do whatever you want on the `hold` event
})
}
selector.addEventListener('click', function(event) {
if (stopPropagation) { event.stopPropagation(); return false; }
// regular event code continues here...
}
Since mousedown and click events are overlapping, we want the click event to not be triggered when we are trying to get the hold state. This little helper flag variable stopPropagation does the trick.
I am trying to make a swith on / off javascript, but I have a problem: I click always comes in my first class despite my class change.
I have always the same result : on->on or off->off. I check in Firebug my html is changed correctly...
Here my simplified code :
$('.off').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
alert('off');
$(this).removeClass('off');
$(this).addClass('on');
});
$('.on').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
alert('on');
$(this).removeClass('on');
$(this).addClass('off');
});
if anyone has a suggestion, I would be very grateful !!
The event handlers are bound on pageload, so changing the class won't change the event handlers, as they are attach to whatever elements existed at the time of binding. To attach them to future elements, i.e. when you change the classes, you'll need delegated event handlers, but an easier solution in my opinion is to just toggle the classes or use a flag:
$('.off').on('click', function(e) {
e.preventDefault();
var state = $(this).is('.off') ? 'on' : 'off';
alert(state);
$(this).toggleClass('off on');
});
FIDDLE
It can be confusing, but even if you remove the .off class, the event handler is still bound to the same element, as it had the .off class at the time of binding!
Either .off or .on does not exist when you first bind with .on. You need to use event delegation, or you can rewrite this so that it's bound to another class and maintain on/off state. I will show you both methods.
Delegation
$(document).on('click', '.off', function(e) {
$(this).removeClass('off').addClass('on');
}).on('click', '.on', function(e) {
$(this).removeClass('on').addClass('off');
});
http://jsfiddle.net/ExplosionPIlls/2PHJg/
Internal state
$(".switch").on('click', function () {
if ($(this).is('.off')) {
$(this).removeClass('off').addClass('on');
}
else {
$(this).removeClass('on').addClass('off');
}
});
http://jsfiddle.net/ExplosionPIlls/2PHJg/1/
This problem is caused because $('.on') and $('.off') only gets evaluated once, when your javascript code runs.
You have to use event delegation to solve the problem. Modify the code the following way. I describe below what it means.
$('#container').on('click', '.off', function(e) {
e.stopPropagation();
e.preventDefault();
alert('off');
$(this).removeClass('off');
$(this).addClass('on');
});
$('#container').on('click', '.on', function(e) {
e.stopPropagation();
e.preventDefault();
alert('on');
$(this).removeClass('on');
$(this).addClass('off');
});
In the place of #container use a selector which selects a parent of your .on / .off elements. In the second parameter of your on() call, youy have to specify the element for which you want to listen for events.
This way the event handler will run properly, even if the class of your elements change.
The problem is that the event handlers are bound when the code first runs, so when the class changes, the event handlers aren't rebound. One way to fix this is to assign the element a class that doesn't change, and use that for the event handler.
Example:
$('.button').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
$(this).toggleClass('off on');
});
You can see a working example at http://codepen.io/skimberk1/pen/GJhna.
I'm trying to fire a click event on the innermost element in the HTML tree, but since there is a click even tied to its parent container, both events are fired, which is not what I need. I have fixed this before with stopPropagation(), but I can't seem to get it to work today.
jQuery('#parent li').click(function() {
jQuery(this).children('.contained').slideDown();
});
jQuery('.contained').click(function() {
Query(this).slideUp();
});
and let's say here is our HTML:
<ul id="parent">
<li>
click to show more
<p class="contained">click to hide</p>
</li>
</ul>
I believe this won't validate since it has a p contained within an li, but let's ignore that momentarily for simplicity's sake. How can I have the inner element slideUp() without have the parent click even trigger it to slideDown() immediately after?
return false to stop the bubbling:
jQuery('.contained').click(function() {
Query(this).slideUp();
return false;
});
Note that returning false also prevent the default behavior of the event.
Read more here.
Or use the event object's stopPropagation function:
jQuery('.contained').click(function(e) {
Query(this).slideUp();
e.stopPropagation();
});
The answer is to stop the propagation of the event. You can use stopPropagation and its twin, stopImmediatePropagation to do this or you can both stop propagation and prevent the default action by returning false from the handler. The stopPropagation method will prevent event bubbling, that is, the propagation of the event up the DOM tree. The stopImmdiatePropagation will do that but also prevent other handlers at the same level from firing. Returning false is equivalent to using stopPropagation and preventDefault on the event.
Two ways to do it, stop the propagation or combine the two click handlers and adjust code according to event.target
Target method:
jQuery('#parent li').click(function(event) {
var $tgt=jQuery(event.target)
if (!$tgt.is('.contained') ){
jQuery(this).children('.contained').slideDown();
}else{
$tgt.slideUp();
}
});
I have some jQuery code to close my menu:
$('body').click(function(){
$('#menu').hide();
});
$("#menu").click(function(e) {
e.stopPropagation();
return false;
});
However on my #menu element I have some elements that have click events attached to them:
$('.menu_elem').live("click", function(){
//Do something
});
My problem is that the e.stopPropagation() is preventing my click events for my menu. How can I avoid this?
You can use e.target to include or exclude the element in condition for stopPropagation,
$("#menu").click(function(e) {
if(e.target.id == "menu")
{
e.stopPropagation();
return false;
}
});
I'm not sure I understand your HTML exactly, but if #menu is the root of your menu and .menu_elem are menu items in the menu, then you could change your delegated event handling to to be captures at #menu like this:
$("#menu").on("click", ".menu_elem", function () {
// do something
});
This has the following advantages:
It changes the delegated event handling to capture the bubbled events at #menu so it doesn't need propagation beyond #menu in order to work so you don't have to change your.stopPropagation() code.
It switches away from (the now deprecated) .live() to the replacement .on() which gives you more control over where the bubbled events are captured.
Write up your code that you want to execute and call it before you call stopPropagation..
$("#menu").click(function(e) {
// Your code here
e.stopPropagation();
return false;
});
Or use the target attribute to contain your click event