I'm trying to make an extension with 'pick' functionality: letting the user click on any element on the page and see the xpath for it.
However, to make it usable I have to prevent the element from reacting on clicking: I don't want clicking on hyperlinks to forward me to another page, buttons to submit forms, etc., etc.
How would I do that?
UPD: I need it only for Chrome
The cleanest way in my opinion would be to bind one event handler to body in the capturing phase and prevent the event from propagating/the default behavior.
You can get a reference to the clicked element with event.target:
document.body.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
console.log(event.target);
}, true);
The advantage is that this event handler will be the very first that is triggered, no matter which other event handlers are bound to elements in the page (unless of course the page binds a similar event handler to body, but usually event handlers are bound in the bubbling phase).
For more information see quirksmode.org - Event order and MDN - addEventListener.
DEMO
For a CSS only solution:
* {
pointer-events: none;
}
Try this
$('body *').on('click',function(e){
return false;
});
In your click event handler make sure you either call preventDefault() in the event object, or return false from your function. For example:
function myClickHandler(e) {
e.preventDefault() // e is the event object
// Do your click stuff here
.
.
.
return false; // not required if you've called e.preventDefault()
}
Related
I am cloning a div tag when user click on available div. After cloning it I am inserting it after clicked div tag. This new div tag also has cross link to delete it. However when I click on cross link it does delete that particular div. It means it is working. Now I also have one function named foo. This method is called upon adding and deleting div tag. But when I click on delete link, this foo function is called twice. I know its reason because I am attaching click event to both parent of delete link and to delete link itself therefore, it is called twice. But How can I make it call once upon both adding and deleting div element?
Here my JSFIDDLE
Html:
<div class="container">
<div class="bx"></div>
</div>
Here is js
$('body').on('click', '.bx', function (e) {
var clone = $(this).clone();
clone.append('<a class="bx-del" href="#">X</a>');
$(this).after(clone);
foo();
});
$('body').on('click', '.bx-del', function (e) {
e.preventDefault();
$(this).parent().remove();
foo();
});
function foo() {
console.log('foo');
}
My original answer was :
Assuming .bx-delis inside .bx(better to add html as well in the question) then adding e.stopPropagation() to the .bx-delcallback should work.
E.g.
$('body').on('click', '.bx-del', function (e) {
e.preventDefault();
e.stopPropagation();
$(this).parent().remove();
foo();
});
Documention here
It has been pointed out that both events are actually attached to the body and run as delegated events. This solution seems to work but the question is whether or not it is reliable. The question here is in what order are delegated events run? Are they always run "depth first" or based on the order they were added or what? Running them depth first would be the most logical in my view, but performance considerations will play a large role here too.
I have been unable to find any hard documentation on this. The jQuery .on() documentation says
jQuery bubbles the event from the event target up to the element where
the handler is attached (i.e., innermost to outermost element) and
runs the handler for any elements along that path matching the
selector.
which could be interpreted as saying that, but could also be an explation of the concept of delegation.
Thus a safer solution to the the original problem, in my view, would be to combine the two lick events into one:
$('body').on('click', '.bx', function (e) {
var t = $(e.target);
if( t.hasClass('bx-del') || t.closest('.bx-del').length > 0){
e.preventDefault();
t.closest('.bx').remove();
foo();
} else {
var clone = $(this).clone();
if( $('.bx-del', clone).length == 0 ){
clone.append('<a class="bx-del" href="#">X</a>');
}
$(this).after(clone);
foo();
}
});
(I have also fixed so that cloning a div with a delete button doesn't add a second delete button).
This is what event.stopPropagation() is for (docs). It prevents the event from bubbling up into the DOM tree. If you add e.stopPropagation() to your delete link click handler, it will not bubble up to the div that contains it and trigger the click handler there too:
As pointed out in the comments, this is not correct, even though it appears to work correctly. Both event handlers are attached to body, and only via a 'trick' run on specific elements. The event is already at the body element, and will therefore not bubble any further. Furthermore, event.stopPropagation() should not stop other handlers from execution, event though they seem to do that right now anyway. The correct function to use here is event.stopImmediatePropagation() (docs at jquery).
$('body').on('click', '.bx-del', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
$(this).parent().remove();
foo();
});
Because you cannot stopPropagation to the <body> tag when the event has already propagated to the <body> tag and both your events are on the <body> tag, I would suggest just attaching the delete event handler right to the delete X object and not use propagation for that event handler. You can then stopPropagation of that click so it won't be seen by the parent at all. In your case this is fairly easy.
Working demo: http://jsfiddle.net/jfriend00/7CDNG/
$('body').on('click', '.bx', function (e) {
var clone = $(this).clone();
clone.append('<a class="bx-del" href="#">X</a>');
$(this).after(clone);
clone.find('.bx-del').on('click', function(e) {
$(this).parent().remove();
foo();
// stop propagation and prevent default
return false;
})
foo();
});
function foo() {
console.log('foo');
}
Alternatively, you could put the .bx handler on the document object and the .bx-del handler on the body object and then you could stopPropagation up to the document object from the .bx-del handler. But, it seems in this case, it is much cleaner to just attach the delete event directly to the delete object and not use delegated event handling to avoid any possible misinterpretation of the click event.
Apparently the other answers are getting away with using .stopPropagation() on one body event handler to stop the other one from firing. Here's a quote from the jQuery documentation for .stopPropagation(): "I think you're getting lucky that's all. This is taken directly from the jQuery documentation for stopPropagation(): "Note that this will not prevent other handlers on the same element from running." Since both of these event handlers are on the body object, it does not seem like a wise and safe move to use .stopPropagation() from one to stop the other from running. It's my opinion that that technique is not safe and is not the conceptually correct way of solving this problem.
I have a page with div and a button on it. I have added onClick event to both of them. Now when I click the button on the div the onClick of the div is also being executed. Is there any way that I can avoid this?
Thank You,
Try this, pass the event as parameter to your onclick event and call
event.stopPropagation();
event.preventDefault();
Your onclick event assignment should be:
$(button).click(function(event) {
// script here
event.stopPropagation();
event.preventDefault();
});
In your click handler you might want to use "stopPropagation" for example:
$("button").click(function(e) {
// handle this event
// ...
// don't pass this event up to parent handlers
e.stopPropagation();
} );
There's also a related function that you might want to read about called "preventDefault" which tells the browser not to do what it normally does automatically (e.g. submit a page when a submit button is clicked)
See also:
https://developer.mozilla.org/en/DOM/event.stopPropagation
http://api.jquery.com/event.stopPropagation/
What's the effect of adding 'return false' to a click event listener?
http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/
in the listener for the link element, you can put e.stopPropagation(), which should fix it (if you're using event bubbling).
If you aren't using jQuery, make sure you set the useCapture parameter of addEventListener() to False info - MDN; you want to be sure you know which direction your events are moving through the DOM (you want them to bubble).
You need to prevent the button onClick event from bubbling to the Div. So basically at the end of your onClick function for the button, once you have done all you logic, you need to call event.stopPropagation()
If none of the above work, try out:
$("button").click(function(e) {
e.stopImmediatePropagation();
});
I have a div, I want to set it so that when I click on something else, it would hide the div.
So I did
$('body').click(function(){
if(loginOpened)
{
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
}
loginOpened=false;
});
However, even when I click in the div itself the event is fired, is there anyway to prevent this?
You can stop it using
e.stopPropagation(); if there is a click event bound to the <div /> tag.
See event.stopPropagation()
Prevents the event from bubbling up
the DOM tree, preventing any parent
handlers from being notified of the
event.
Otherwise you can check the target of the event inside the body click. Check whether event.target is the same as your div.
See event.target
Just check the event.target. If the element that triggered the event is your div do not execute the code.
$('body').click(function(evt){
evt = evt || window.event
if ($(evt.target) != $('#loginWindow')) {
if(loginOpened)
{
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
}
loginOpened=false;
}
});
Yes, but of course Microsoft and the rest of the world came to different conclusions about how to do it. This site gives a good clear rundown of what's needed: http://www.quirksmode.org/js/events_order.html .
I don't use jQuery but the jQuery way appears to be event.stopImmediatePropagation(); as seen in this question: jQuery Multiple Event Handlers - How to Cancel? .
A couple of changes from John's code:
$('body').click(function(ev){
// jQuery means never having to say "window.event"!
// Also, code's cleaner and faster if you don't branch,
// and choose simple breaks over more complex ones
if(!loginOpened) return;
// Lastly, compare using the DOM element;
// jQuery objects never compare as the "same"*
if (ev.target == $('#loginWindow').get(0)) return;
$('#loginWindow').animate({
'width':'0px',
'height':'0px'
},"fast");
loginOpened=false;
});
If trapping it in the body event doesn't work for you, you can just add a simple event handler to the div:
$('#loginWindow').click(function (ev) { ev.stopPropagation(); });
I was going to say return false, but that would prevent other things from firing off the div. stopPropagation just keeps the event from bubbling outward.
I could be really picky, of course...
//Delegation via the document element permits you to bind the event before
// the DOM is complete; no flashes of unbehaviored content
$(document).delegate('body', 'click', function(ev){
//You only have one instance of an id per page, right?
if(!loginOpened || ev.target.id == 'loginWindow') return;
//quotes and px? not necessary. This isn't json, and jQ's smart
$('#loginWindow').animate({width:0,height:0},"fast");
loginOpened=false;
});
* Don't believe me? Try:
jQuery('#notify-container') == jQuery('#notify-container')
Then try
jQuery('#notify-container').get(0) == jQuery('#notify-container').get(0)
Whats the easiest way to temporarily disable all mouse click/drag etc events through javascript?
I thought I could do document.onclick = function() { return false; }; ...etc, but that's not working.
If the objective is to disable click on the whole page then you can do something like this
document.addEventListener("click", handler, true);
function handler(e) {
e.stopPropagation();
e.preventDefault();
}
true argument in addEventListener would ensure that the handler is executed on the event capturing phase i.e a click on any element would first be captured on the document and the listener for document's click event would be executed first before listener for any other element. The trick here is to stop the event from further propagation to the elements below thus ending the dispatch process to make sure that the event doesn't reach the target.
Also you need to stop default behavior associated with event target elements explicitly as they would be executed by default after the dispatch process has finished even if the event was stopped propagating further from above
It can be further modified to use selectively.
function handler(e) {
if(e.target.className=="class_name"){
e.stopPropagation();
e.preventDefault();
}
}
handler modified this way would disable clicks only on elements with class "class_name".
function handler(e) {
if(e.target.className!=="class_name") {
e.stopPropagation()
}
}
this would enable clicks only on elements with class "class_name".
Hope this helped :)
Dynamically disable all clicks on page
let freezeClic = false; // just modify that variable to disable all clics events
document.addEventListener("click", e => {
if (freezeClic) {
e.stopPropagation();
e.preventDefault();
}
}, true);
I often use it while loading or to avoid user to accidentally clic twice on an action button. Simple and performance friendly :)
Please check this working example
Alternative CSS way
Another one that I really like because of the visual feedback the user have:
/* style.css */
.loading {
cursor: wait; /* busy cursor feedback */
}
.loading * {
/* disable all mouse events on children elements */
pointer-events: none;
}
A simple example to dynamically add the .loading class:
const elm = document.getElementById('myElm')
elm.classList.add('loading')
myAsyncFunction().then(() => elm.classList.remove('loading'))
If you want absolutely nothing draggable/clickable, disabling typing in input fields etc, I'd consider showing a absolutely positioned transparent div over the entire page, so that every click will be on the div, which will do nothing. That will grant you swift and neat switching on and off of this click-disabler, without having to register heaps of listeners
The winning answer works well, but if you had pass the capture true boolean value, at the moment you want to remove the listener, you have to pass the exact same value. Otherwise, the listener removal will not work.
Example:
listener addition
document.addEventListener('click', DisableClickOnPage.handler, true);
listener removal
document.removeEventListener('click', DisableClickOnPage.handler, true);
Doc: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
window.addEventListener("click", (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}, true)
If we added a listener to document instead of window anyone can add a listener to window and it works. Because of document child of window and its events trigger always after window events.
We use 3 method of Event object.
stopPropagation for prevent all capturing and bubbling
stopImmediatePropagation for prevent same listeners (e.g. another window click listeners)
preventDefault for prevent all user agent event (e.g anchor href or form submit)
If onclick = null has been executed how to revoke the onclick event to normal functioning.. or
Link text
<script type="text/javascript">
function yourFunction(anchor)
{ if(anchor.disabled) return;
/* Your function here */
}
</script>
This article would probably be useful:
http://www.computerhowtoguy.com/how-to-use-the-jquery-unbind-method-on-all-child-elements/
One part in particular is a recursive function that removes all click events. Remember that jQuery will remove click events IF the click event was created using jQuery. the function given in the article will remove both those created with jQuery and those that were not. The function given is this:
function RecursiveUnbind($jElement) {
// remove this element's and all of its children's click events
$jElement.unbind();
$jElement.removeAttr('onclick');
$jElement.children().each(function () {
RecursiveUnbind($(this));
});
}
You would call the function like this:
RecursiveUnbind($('#container'));
That function takes a jQuery object parameter, but you could easily change it up to pass a string as the name of the ID for the element, or however you think is best.
To prevent the default behavior of an event, use event.stopPropagation() and event.preventDefault() in your event handler. And don't forget, return false; is another method for indicating that you want to cancel the default action...
The Event property returnValue indicates whether the default action for this event has been prevented or not. It is set to true by default, allowing the default action to occur. Setting this property to false prevents the default action. (Source: MDN Web Docs: Event.returnValue.)
Typically, we return a value from any function when it has any meaningful or useful purpose -- return false to cancel an event is meaningful because it indicates a failed event, and it's useful because the event-handler uses it.
For greatest cross-browser compatibility, remember to return false;...
document.addEventListener("click",handler,true);
function handler(e){
e.stopPropagation();
e.preventDefault();
return false;
}
I have an onclick event attached to a region in my page that causes a certain action to fire when the user clicks in it (naturally). I recently added an image to that region. When the user clicks on that image, I want another action to occur, and I do NOT want the action associated with the entire region to occur. However, I find that both events are, in fact fired when one clicks the image. How do I suppress the region-wide action when the image is clicked?
The issue you are running into is known as event bubbling. The click event of the image bubbles up to all parent elements of that node. You want to cancel bubbling.
The best way to do this that works across all browsers is by using a JavaScript framework. jQuery has a very simple way to do this. Other frameworks have similar mechanisms to cancel bubbling, I just happen to be most familiar with jQuery.
For example, you could do something like this in jQuery:
$('img').click(function () {
// Do some stuff
return false;// <- Cancels bubbling to parent elements.
});
Darit is correct, you need to stop the event from bubbling (propagating):
function imgEventHandler(e) {
// ^notice: pass 'e' (W3C event)
// W3C:
e.stopPropagation();
// IE:
if (window.event) {
window.event.cancelBubble = true;
}
}
In the event handler for the image do
event.cancelBubble = true;
and then at the end do
return false;