I want to close the div if someone clicked outside that div. I have the below code:
$('body').click(function(e) {
$('div.test').slideUp('slow');
});
$('div.test').live('click',function(e) {
e.stopPropagation();
});
But the issue is that when someone click inside the div, the div itself is closing. I want to prevent that. After debugging I found a weird stuff the debugger is hitting the $(body).click first instead of $(div.test), May I know the reason for this? Can you help me in fixing the issue?
The problem is with your use of live.
live is a way of saying "bind a handler to the root element and capture any events that originated on an element matching a selector". It's a short form of delegate. This is possible because of "bubbling": events on elements are triggered on the element's ancestors as well.
If you do not specify otherwise, live binds the event handler to the document. The event handler on the body will be triggered first since the event won't have bubbled up to the document handler, where the e.stopPropagation() is.
The easiest solution would be to change live to click:
$('div.test').click(function(e) {
If you need to use live, introduce a container element, and handle the event there. I'll use delegate as I prefer its syntax, but you could use live if you preferred:
$('#container').delegate('div.test', 'click', function(e) {
e.stopPropagation();
});
The event is handled on #container and propagation is stopped, so the event never reaches the body's event handler.
What happens if you handle the body click with live() too?
I believe the live click handler doesn't propagate the event in the same way as a standard click. See this documentation.
I believe the problem arises because you are setting a click handler to <body>
I tried the same thing with <p> instead of <body> and it seems to work fine.
Here's a relevant fiddle:
http://jsfiddle.net/seNXV/7/
live() does not stop propagation. Says do in the jQuery docs.
You need to use delegate()
Related
I have kind of strange problem.
I'm trying to add a couple of events to som DOM elements (all existing, some initially hidden:
$self.on("focus", function () {
$self.next().css("display", "inline-block");
});
$self.on("blur", function () {
$(this).next().hide();
});
$self.parent().find(".icon-ok").on("click", function() {
console.log("icon.ok")
});
You can see the relevant part of the DOM here (self is the span user-name):
Later on, the element eventually because visible and I can click on it. However, the event handler is never called. If I remove the blur event, than the click event works. However, I need both.
What's going on here?
How can I fix it?
Looks like the blur cancels out the click (due to event order) but using mousedown instead of blur may help you get both.
UPDATE: Added code based on comment
$self.parent().find(".icon-ok").on("mousedown", function() {
console.log("icon.ok")
});
Your problem might be the classic delegation problem, where in the element is not available in the DOM when the event is bound.
Delegate the event and see if that solves your problem.
$self.on("click", ".icon-ok", function() {
console.log("icon.ok")
});
User $self if that element is visible or any closest ancestor that you can find which is always present in the DOM.
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.
I have element with stopPropagation, but within that element I have another element which I need to be able to use for event. But because it's child element of the one with stopPropagation. It's not working. Is there some way to enable propagation on element within element with stoped Propagation.
Thank you...
Can't you simply trigger the event programmatically on the other element?
$('#firstElement').click(function(e){
e.stopPropagation();
$('#anotherElement').trigger("click");
});
By default many events bubble up the DOM, so the click handler you have will obviously affect parent elements - it seems like you'd have an easier time using e.preventDefault() rather than e.stopPropagation()
See http://css-tricks.com/return-false-and-prevent-default/ for a great explaination on the differences
I have the following jQuery:
$('.io-sidebar-section').click(function () {
console.log('Section Clicked');
$(this).next().fadeToggle('fast',function(){});
});
$('.io-sidebar-section-advanced-toggle').click(function(){
$(this).parent().next().children('.io-sidebar-link-advanced').fadeToggle('fast',function(){});
});
the advanced toggle is inside of a sidebar section. When I click on the advanced toggle, it executes the sidebar section click.
How can I seperate these two out?
You can use the stopPropagation method of the event object inside the click event handler for the child element:
$('.io-sidebar-section-advanced-toggle').click(function(e){
e.stopPropagation();
$(this).parent().next().children('.io-sidebar-link-advanced').fadeToggle('fast',function(){});
});
From the jQuery docs, here's what stopPropagation does:
Prevents the event from bubbling up the DOM tree, preventing any
parent handlers from being notified of the event.
As mentioned in the comments, if you prefer you can alternatively use return false in the event handler (in this particular case, as far as I can tell anyway - it will also cause preventDefault which may not be what you want to happen). My personal preference is to use stopPropagation but it's completely up to you.
You can avoid events bubbling up by using jQuery's bind function and preventBubble argument.
http://api.jquery.com/bind/
Is there any way to prevent a click from an <a> triggering delegated click handlers on its parent, while allowing the the <a>'s default behavior to occur (navigating to the href).
Here's an example that illustrates what I'm asking.
<div class="top">
<div class="middle">
link
</div>
</div>
And my JavaScript:
$(".top").delegate(".middle", "click", function(event) {
alert("failure");
});
$(".top").delegate(".link", "click", function(event) {
// ???
});
In this case, I want to be navigated to google.com when I click the link, but must NOT see the alert("failure") on my way out.
There are a few restrictions to the solution:
All event handlers must be delegated off of $(".top"), as I potentially have thousands of these in the page.
The navigation must be accomplished using browser default behavior, rather than window.location = $(this).attr("href") or similar
Using normal event binding, I could do an e.stopPropagation() in a click handler for the <a>, but that won't work due to the nature of delegation. jQuery provides another method called .stopImmediatePropagation() that describes what I want (preventing other handlers on current element, in this case the element that holds the delegated handlers), but does not actually accomplish it in this case. That might be a bug in .delegate(), I'm not sure.
Returning false from the <a>'s click handler will prevent the other handler from running, but will also do a .preventDefault(), so the browser will not navigate. Basically, I'm wondering what return false; does that e.stopImmediatePropagation(); e.preventDefault(); does not. Based on the docs, they should be equivalent.
For a live demo of the above code, here's a JSFiddle: https://jsfiddle.net/CHn8x/
event.stopImmediatePropagation() is indeed what you're after, but remember that order matters here since .delegate() listens at the same level, so you need to reverse your bindings, like this:
$(".top").delegate(".link", "click", function(event) {
event.stopImmediatePropagation();
});
$(".top").delegate(".middle", "click", function(event) {
if(!event.isPropagationStopped())
alert("failure");
});
Here's a working version of your demo with this change
The order you bound the handlers is the order they will execute, so you need that .link handler to execute and stop the propagation before the other handler runs, checking it with event.isPropagationStopped() or event.isImmediatePropagationStopped().
This normally isn't an issue at different levels, but since .delegate() is listening on the same element, it does matter.