Here's a simplified example of the problem I'm having. Say I have this HTML:
<div id="test">Hello</div>
I have the following event handler attached to this div:
$("#test").on("click", function() {
console.log("Clicked test!");
$(document).one("click", function() {
console.log("Clicked on document!");
});
});
Here's a jsFiddle of this example.
If I click on Hello, ideally I would only want "Clicked test!" to appear in my console, and for "Clicked on document!" to appear after I click a second time. However, both log messages appear, as the click event bubbles up to the document object and runs this new click event. Is there a way to prevent this from happening without using stopPropagation, which may have other unintended side effects?
My solution is kind of hacky, but it does work. If you set the document click handler asynchonously, the event doesn't bubble up:
$("#test").on("click", function(e) {
console.log("Clicked test!");
setTimeout(function(){
$(document).one("click", function() {
console.log("Clicked on document!");
});
}, 10);
return true;
});
See the modified fiddle: https://jsfiddle.net/voveson/qm5fw3ok/2/
Or using on and off with selectors:
$(document).on("click", "#test", add_doc_click)
function add_doc_click() {
console.log("Clicked test!");
$(document).on("click", function (e) {
console.log("Clicked on document!");
})
$(document).off("click", "#test", add_doc_click)
}
https://jsfiddle.net/y2q1gocu/
EDIT: to have test and clicked each time:
$(document).on("click", "#test", add_doc_click)
function add_doc_click() {
console.log("Clicked test!");
$(document).on("click", function (e) {
console.log("Clicked on document!");
})
$(document).on("click", "#test", function (e) {
console.log("Clicked test!");
})
$(document).off("click", "#test", add_doc_click)
}
https://jsfiddle.net/y2q1gocu/1/
Assuming nothing should happen on the third click, add these two lines at the end of the click handler:
$(this).off('click');
return false;
Fiddle
Incase you want to click Hello once and then remaining on document.
$( "div" ).one( "click", function() {
console.log("Clicked test!");
event.stopPropagation();
});
$(document).on("click", function() {
console.log("Clicked on document!");
});
https://jsfiddle.net/qm5fw3ok/3/
You can use a class that flags whether or not the element has been clicked on or not.
$("#test").on("click", function(e) {
console.log("Clicked test!");
if($(this).hasClass('clicked')){
$(document).one("click", function(e) {
console.log("Clicked on document!");
});
}else{
$(this).addClass('clicked');
}
});
Related
In a script I'm writing with JQuery I'm trying to add a click handler to a div, but ignoring clicks on the children a tags inside it.
You can see a JSFiddle of how I'm currently trying (and failing) to make it happen here: http://jsfiddle.net/q15s25Lx/1/
$(document).ready(function() {
$(document).on('click', '.post:not(a)', function(e) {
alert($(this).text());
});
});
<div class="post">This is some text in a div. Click me please.</div>
In my real page, the a tags all have their own click handlers, so I need to be able to listen for those concurrently.
So, ideally I'd like to use something like the :not() selector to ignore clicks on this particular handler.
Is something like this possible?
You'll need to add another handler that acts on the anchor and stops the event from propagating:
$(document).on('click', '.post a', function (e) {
e.stopPropagation();
e.preventDefault();
});
Without this, when you click the a the event bubbles up to the parent .post, and the handler fires on that anyway.
You need to stop event propagation to child elements using .stopPropagation():
$(document).on('click', '.post a', function(e) {
e.stopPropagation();
});
Working Demo
Just return false; in the end of event handler.
$(document).on('click', '.post', function (e) {
alert($(this).text());//will show entire text
});
$(document).on('click', '.post a', function (e) {
alert($(this).text());//will show 'text'
return false;
});
working fiddle: http://jsfiddle.net/q15s25Lx/2/
return false will server as both e.preventDefault() &
e.stopPropagation()
Try to stop the event from bubbling up the DOM tree using stopPropogation()
$(document).ready(function() {
$(document).on('click', '.post a', function(e) {
e.stopPropagation();
alert($(this).text());
});
});
Fiddle Demo
All of the other posts did not explain why your code failed. Your selector is saying : Find an element that has the class post and is not an anchor. It is NOT saying if a child was clicked and was an achor do not process.
Now there are two ways to solve it. One is to prevent the click from bubbling up from the anchors. You would add another listener on the anchors.
$(document).on('click', '.post a', function (evt) {
evt.stopPropagation(); //event will not travel up to the parent
});
$(document).on('click', '.post', function (evt) {
console.log("Click click");
});
Or the other option is not to add a second event, but check what was clicked.
$(document).on('click', '.post', function (evt) {
var target = $(evt.target); //get what was clicked on
if (target.is("a")) { //check to see if it is an anchor
return; // I am an anchor so I am exiting early
}
console.log("Click click");
});
Or jsut let jquery handle it all for you. return false
$(document).on('click', '.post:not(a)', function() {
alert($(this).text());
return false;
});
I have this code in my script:
$(document).ready(function() {
$('*').not('div#user').click(function() {
$('div#userSettings').hide();
});
$('div#user').click(function() {
$('div#userSettings').toggle();
$('div#profileSettings').toggleClass('rotate');
});
});
I need the div#userSettings to be hidden whenever anything but it's button or itself is clicked, and I want it to appear only when I click on the div#user.
the toggleclass does still work in this, just that the div#userSettings does not appear at all
You can stop the event propagation
$(document).ready(function () {
$(document).click(function (e) {
$('#userSettings').hide();
})
$('#user').click(function (e) {
e.stopPropagation();
$('#userSettings').toggle();
$('#profileSettings').toggleClass('rotate');
});
$('#userSettings').click(function (e) {
e.stopPropagation();
});
});
Demo: Fiddle
I created the below html with JavaScript and I want to be able to listen to the click on both the channel_li and client_li.
Generated HTML
<li cid="4" class="channel_li" style="display: list-item;">Random<ul class="client_ul">
<li class="client_li" clid="14" style="">Hanekawa</li></ul>
</li>
The second code snippet is the JavaScript I'm using to generate the elements and assign a click event. The problem I have is that when I click the channel_li nothing happens, and when I click on the client_li it triggers the channel_li listener. Is there anyway of fixing this?
JS
// Some generation code here.
// $li here is the created channel_li element.
$($li).on("click", "li", function() {
console.log("channel click");
});
// More generation code.
// $foo here is the client_li element.
$($foo).on('li', 'click', function () {
console.log("client click.")
});
You will need stopPropagation(): http://api.jquery.com/event.stoppropagation/, because nested elements are in question.
$(document).on("click", "li.channel_li", function() {
alert("channel click");
});
$(document).on("click", "li.client_li", function(e) {
e.stopPropagation();
alert("client click");
});
fiddle: http://jsfiddle.net/W68sa/1/
Your selector is wrong, becoue $li is not a variable or valid selector:
// $li here is the created channel_li element.
$($li).on("click", "li", function() {
console.log("channel click");
});
for
// $li here is the created channel_li element.
$(document).on("click", "li", function() {
console.log("channel click");
});
How you need trigger diferens events use the clase for:
// $li here is the created channel_li element.
$(document).on("click", ".client_li", function() {
console.log("Client click");
});
// $li here is the created channel_li element.
$(document).on("click", ".channel_li", function() {
e.stopPropagation();
console.log("Channel click");
});
Live Demo
Live Demo 2
Description stopPropagation: Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of
the event.
I need to overwrite the events but, the application has an option to return the original events to each element of the document. Any ideas?
For example:
<div class="mydiv">
</div>
$(document).delegate( '.mydiv', click', function () {
alert('This is the original event my event!');
});
$(document).delegate( '.mydiv', 'click', function() {
alert('Do this and ignore de previous...');
// For example: How to return the original event when mouseleave event will executed?
});
$(document).delegate( '.mydiv', 'mouseleave', function() {
// return the original event of mydiv
});
Use undelegate function before creating new click function
Docs http://api.jquery.com/undelegate/
try to check click event in functions
$(document).delegate( '.mydiv', click', function ()
{
if(clicked){
return;
}
alert('This is the original event my event!');
});
$(document).delegate( '.mydiv', 'click', function() {
if(!clicked){
return;
}
alert('Do this and ignore de previous...');
});
So I have two click events for "button-open" and "button-close". I have one button that switches from "button-open" to "button-close" on click. So when i click it again, it should fire the event for "button-close" but instead it fires the event for "button-open" again.
Demo : jsFidde
Here's my code:
Button​
<script>
$(document).ready(function() {
$(".button-open").click(function() {
$(this).removeClass("button-open").addClass("button-close");
alert("Open Was Clicked");
});
$(".button-close").click(function() {
$(this).removeClass("button-close").addClass("button-open");
alert("Close Was Clicked");
});
});
</script>
Use on() instead of click(), since you need to bind to an element that doesn't yet exist when you initially bind it.
$(document).on('click', '.button-open', function() {
$(this).removeClass("button-open").addClass("button-close");
alert("Open Was Clicked");
});
$(document).on('click', '.button-close', function() {
$(this).removeClass("button-close").addClass("button-open");
alert("Close Was Clicked");
});
DEMO.