I've tried searching for an explanation to my issue below but it's possible the keywords I used are to ambiguous.. so I turn to you.
I'm trying to implement a click outside menu to close based on this code here which is:
$('#menuscontainer').click(function(event) {
//your code that shows the menus fully
//now set up an event listener so that clicking anywhere outside will close the menu
$('html').click(function(event) {
//check up the tree of the click target to check whether user has clicked outside of menu
if ($(event.target).parents('#menuscontainer').length==0) {
// your code to hide menu
//this event listener has done its job so we can unbind it.
$(this).unbind(event);
}
})
});
However it seems the function in $('html').click... gets executed when clicking on the #menucontainer so it just open and immediately closes.
I've simplified it to:
$('.trig').click(function () {
$('.menu').show();
$('body').click( function () {
alert('boo');
});
});
Here's the JSFiddle link.
As you can see alert gets executed when .trig is clicked on. So instead of just creating the even listener, it seems to already be listening.
Can someone please explain this to me? Thanks.
Events bubble to parents also.
You can prevent this by using event.stopPropagation()
$('.trig').click(function (e) {
e.stopPropagation();
$('.menu').show();
$('body').click( function () {
alert('boo');
});
});
Since you are adding a click handler to the body before the event is over it is also being triggered on the body
Reference: https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
DEMO
Related
I'm making a popup menu. The user clicks on it to show the menu, then if they click outside the popup menu I want to hide it.
I can find many solutions (most popular is here: How do I detect a click outside an element?) but they all seem to have the same issue.
They rely on handling clicks that bubble up to the window element.
Their Logic:
All clicks bubble up to window element. Handle those clicks - if menu is open, then close it. Also call preventDefault to stop any links being followed (let's just say that the user happens to click on a link when they are clicking outside the menu - we don't want to follow that link)
$(window).click(function(e) {
if (!e.isDefaultPrevented()) {
if($('.mainNav').hasClass('menuVisible')){
//stop any other actions happening (e.g. following a link)
e.preventDefault();
//Hide the menus
$('.mainNav').removeClass('menuVisible');
}
}
});
The issue
If the thing the user clicks on happens to have an onclick event itself then that code still gets fired. Elements lower down the tree get the click even first, so I cannot use preventDefault or stopPropagation to stop these events..
Any ideas how to fix it? My only idea is to put a transparent div across the whole screen on top of everything to catch the clicks first?
You need to use addEventListener() and the useCapture property. the useCapture property allows events from object higher in the DOM tree to be triggered first. You can then prevent your normal click behaviour from occurring:
var button = document.getElementById("myButton");
var response = document.getElementById("myResponse");
var windowClick = function (evt) {
response.innerHTML += "<p>The Window</p>";
evt.stopPropagation ();
}
var buttonClick = function (evt) {
response.innerHTML += "<p>The Button</p>";
evt.stopPropagation ();
}
button.addEventListener("click", buttonClick);
// If true, the window event fires first, if false, the button fires first.
var useCapture = true;
window.addEventListener("click", windowClick, useCapture);
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="myButton">Hello!</button>
<div id="myResponse">Who Clicked?</div>
</body>
</html>
Updated
I originally misunderstood that we were trying to stop inline onclick events from firing. I found a potential solution from another StackOverflow question, you can see it here.
Otherwise, take a look at this:
$('button[onclick]').each(function(){
$(this).data('onclick', this.onclick);
this.onclick = function(event) {
if($('.mainNav').hasClass('menuVisible')) {
return false;
};
$(this).data('onclick').call(this, event || window.event);
};
});
It overrides the elements click handler. I've updated your jsFiddle to show it in action.
you can add a class to the body when menu is opened, and attach an event listener to the click event of body which will hide the menu and remove the listener
when showing the menu
$('body').addClass('menu-open');
$('body.menu-open').one('click', function(e) {
e.preventDefault();
// code to hide your menu goes here
$('body').removeClass('menu-open');
});
Note the usage of .one for attaching the event handler. It automatically removes the event handler after it is executed once.
Ref https://api.jquery.com/one/
My JS looks something like this
$(document).ready(function(){
menuClickHandler();
});
I have ajax based menu, menuClickHandler is used to make it work and resides in a separate JS file. menuClickHandler associates other functions that are associated to menu item. On click of menu item it calls a function associated with the menu item. Lets say I have menu item Jump and a function JumpHandler associated with it. Within JumpHandler there is one simple function as follows
functionA() {
$("div.tree").on("click", ".branch", function(event) {
event.stopPropagation();
//some code
});
}
Scenario:
When the page is first loaded everything is fine, when I click on Jump functionA' gets called and everything works fine. Now if click some other menu item and then click onJumpagain,JumpHandleris called again and hencefunctionA` gets called again resulting in click event on branch being bound twice. Can anyone tell me how do I remove/undelegate the delegated click event so that there is only click event bound to branch.
jQuery version: v2.1.1
You can use .one() instead of .on()
Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
Code
$("div.tree").one("click", ".branch", function(event) {
event.stopPropagation();
//some code
});
if for some reason you have to bind click event inside functionA, then you can try off
functionA() {
$("div.tree").off("click", ".branch" );
$("div.tree").on("click", ".branch", function(event) {
event.stopPropagation();
//some code
});
}
or else you can do this binding outside the functionA since it is attach the event handlers to future branch elements regardless of when you invoke functionA
if you want to ensure that event is only fired once, then
functionA() {
$("div.tree").on("click", ".branch", function(event) {
event.stopPropagation();
//some code
$("div.tree").off("click", ".branch" );
});
}
Because Once the function is called you have initialize a function in jquery which will execute without calling the function again. So before calling any function just turn off the jquery function
example:
$("div.tree").off("click", ".branch" );
functionA();
$("div.tree").off("click", ".branch" );
functionB();
I have a simple div with a link with in:
<div class="mhButton">
<span class="icon-checkmark"></span> Register Animal
</div>
I've have a function that is triggered whenever the 'div.mhButton' is clicked. This function should find 'div.mhButton' child 'a' and click it.
$(".mhButton").on('click', function () {
var a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
This works, however, I get stuck in a loop that runs like 639 times.
I can't comprehend why this runs X amount of times, then continues without error.
Does anyone have a solution on how to prevent this? Along with an explanation on why this happens?
Note* The console is logging the same button, again and again.
Because the a tag is embedded in the button, you are continuously re-firing the event. Events will bubble up, so the anchor will get clicked, and then its parent. It is running until the browser gets tired of running it and then it just stops. The method doesn't actually do anything which is likely why you aren't seeing any issues. You can accomplish your goal a couple of ways:
$(".mhButton").click(function () {
$(this).off('click'); // turn the click handler off in the handler itself.
var a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
If you do this, then you will end up only being able to fire the event once.
Alternatively:
$(".mhButton").click(function (e) {
a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
$("#RegisterAnimal").click(function (e) {
e.stopPropagation(); // prevent the anchor from re-firing the button click
});
Altenatively, you can just style the link to look like a button and avoid the unnecessary click handlers all together.
When you call $(this).find("a").click(); the event will bubble up to the div.mhButton tag and cause your handler to be called again. The reason it runs around 500 times is because it stops with a stack overflow, it does not continue
You can prevent it by checking if the click was the <a> tag itself and not calling click() in that case
Working example: http://jsfiddle.net/mendesjuan/zdkrhh42/
Note Regarding the accepted answer
Bic's second answer almost works, mine is a different approach with fewer side effects. The main problem with calling stopPropagation is that there may be handlers on the whole document that wouldn't get fired in that case. A commmon case is when you have a menu or a dialog that is supposed to hide when you click anywhere else on the page. The stopPropagation approach will prevent the menu from being hidden when they click your button.
$(".mhButton").click(function (e) {
// Only run this handler if the click was on the div, not the link itself
if ( $(e.target).is('a, a *') ) {
return;
}
var a = $(this).find("a").text();
$(this).find("a").click();
});
I want to prevent click event but e.stopPropagation() doesn't work.
I'm trying to write something like Jtable . I use div as pagination buttons(1) and another element is delete button.
I need to disable pagination buttons when delete confirmation box is popping up . After click del or cancel "I want my pagination buttons work again".
Is there any solution?
function deleteit() {
$(".del").click(function() {
$(".divbutton").click(function(e) {
alert(1);
e.stopPropagation();
});
}
$(".deletebtn").click(function() {
deleteit();
});
$(".divbutton").click(function() { // I want to prevent this from click
//ajax send and display data
});
I know that I should use input disabled instead of div, but I need to use div.
edit:add image to make it understandable.
Instead of preventing the click handler... remove the registered handler using .off(), here namespaced event name is used because we want to remove only a very specific handler
function deleteit() {
$(".del").click(function () {
$(".divbutton").off('click.delete')
})
}
$(".deletebtn").click(function () {
deleteit();
});
$(".divbutton").on('click.delete', function () { // I want to prevent this from click
//ajax send and display data
});
Why your code is not working? because stopping propagation will prevent the bubbling up of the event but in your case both the event are registered to the divbutton so both of them will get triggered even if propagation is prevented.
Another way is to use stopImmediatePropagation() even that is not possible here because your delete registers the handler later and it will get executed only after the first one is called
I have a search input box that appears upon rollover of a button. Rather than having its own close button I would like to be able to click anywhere on the page to re-hide the Search.
If I attach a click handler to the document this works fine but the problem being is that the search itself is part oofthe document. So if you click the input (which of course you need to do in order to type in a search) the search disappers.
I had hoped I'd be able to write a function soemthing like this...
$(document).not("#search").click(function(){
$('#search_holder').fadeOut('fast');
});
i.e apply a click handler to the entire document APART from the search. Unfortunately that doesn't work.
so whats the answer?
thanking You in advance
Cancel the click event from propagating when it originates from the button you care about:
$("#search").click(function(event){
event.stopPropagation();
});
You can do it by stopping the click event from bubbling, like this:
$(document).click(function() {
$('#search_holder').fadeOut('fast');
});
$("#search").click(function(e) {
e.stopPropagation();
});
event.stopPropagation() prevents the bubble from going any higher, all the way to document triggering the .fadeOut(), everywhere else (by default) will bubble to document, causing the fade to occur.
Try this Its working perfect for me.
$(document).mouseup(function (e)
{
var searchcontainer = $("#search_container");
if (!searchcontainer.is(e.target) // if the target of the click isn't the container...
&& searchcontainer.has(e.target).length === 0) // ... nor a descendant of the container
{
searchcontainer.hide();
}
});