preventDefault() is insufficient in anchor event delegation in iframe? - javascript

I hope this might be a low-hanging fruit for all you web-dev experts out there:
I have implemented event delegation by attaching a mouse click handler to a parent element of an unordered list of anchor elements (classic navigation design). The document I am working on exists in an iFrame. The handler looks like this:
const handleMouseClick = function(evt) {
if (evt.target.matches('a')) {
evt.preventDefault();
evt.stopPropagation();
console.log('Clicked a tag....', event.target.href);
}
};
Just to provide a full context, I am clicking through an overlay element that takes no pointer events - so it should have no influence on click handling.
Anyway, when clicking on one of the anchor tags, I would like to prevent the iframe from loading the URL referenced in the anchor. The before mentioned click handler, which is attached to a parent, receives the click event just fine and I would have expected that calling event.preventDefault() would do the trick. However, I have to call both
event.preventDefault() and event.stopPropagation() to stop the iframe from loading the link. If I remove either one of them, the iframe loads the link?
My first thought on this is that this is unexpected, when looking at the literature on preventDefault and stopPropagation but I might be missing something. What am I missing - why is event.preventDefault() not sufficient in this case?

Related

How to make the whole page clickable without using any cover elements with Javascript?

With Javascript, I'm looking for a way to make the whole page to redirect the user to another, no matter where they click on the page, and no matter if that element already has a click event listener. I want to redirect them no matter what.
Also, I do not want to use a cover element with fixed style and make them click on that, if possible.
Here's what I've tried so far:
function clickBody()
{
window.location.href = 'http://google.com';
}
document.body.addEventListener("click", clickBody);
It works great, except the fact that it's not redirecting if the user clicks on the anchor tags.
Is there any solution to make this happen?
Add true as the last arg to addEventListener (it means that it's capture event and should be handled before regular events) and stop event propagation and prevent default in your handler to prevent redirect on links click:
function clickBody(e) {
e.preventDefault();
e.stopPropagation();
window.location.href = 'http://google.com';
}
document.body.addEventListener("click", clickBody, true);
You will want to use the capturing phase of the event lifecycle. From MDN
In the capturing phase:
The browser checks to see if the element's outer-most ancestor
() has an onclick event handler registered on it in the
capturing phase, and runs it if so. Then it moves on to the next
element inside and does the same thing, then the next one, and
so on until it reaches the element that was actually clicked on.
In the bubbling phase, the exact opposite occurs:
The browser checks to see if the element that was actually clicked on
has an onclick event handler registered on it in the bubbling phase,
and runs it if so. Then it moves on to the next immediate ancestor
element and does the same thing, then the next one, and so on until it
reaches the element.
function clickBody()
{
window.location.href = 'http://google.com';
}
document.body.addEventListener("click", clickBody, true);
The third parameter here designates the event as capturing. https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
In all likelihood, the javascript should execute fast enough to beat out the default action for the link. But you may want to add event.preventDefault() just to be on the safe side.

Link within a link onClick event - Avoid both click events triggering

I have a link within a link, both with an onClick event.
The outer link works as desired. However, the inner link triggers both onClick events. I would like it so that the outer event is not triggered when the inner link is clicked.
<div onClick="console.log(1)">
Inner
</div>
JSFiddle
Javascript events will propagate up through the tree.
So when you click on the inner anchor it will also emit any click events for elements higher up, so the div element.
To stop this the inner click handler has to prevent the event from propagating with e.stopPropagation();.
However this gets a little messy when you don't register handlers with .addEventListener() in JavaScript.
If you add events this way you can do it like this (first give your anchor an id, say inner) which is nice and easy:
document.getElementById('inner').addEventListener('click', function (e) {
e.stopPropagation();
console.log(2);
});
You can however pass the event into your click handler if you do wish to use the attribute, so:
Inner
//JS
function innerHandler(e) {
e.stopPropagation();
console.log(2);
}
Generally speaking (this is my opinion) i would avoid the latter. Events registered like this are difficult to remove and modify. You can't also easily register multiple handlers to the same element for the same event.
stopPropagation docs

Catching click event while delete thumbnail

I slightly modified FU thumbnail template to hook a click event on it. I also display a delete button (the provided one).
The problem is that when I click on the delete button, the click event bubbles to the rest of the javascript stack.
How can I prevent the delete button to propagate the click event??
(usually you do something like event.stopPropagation()...).
Thanks for your help
If you'd like to prevent any DOM event from bubbling, simply attach an event handler to the element where you would like it to terminate and call stopPropagation() on the Event object. For example, for a click event:
someElement.addEventListener('click', function(event) {
event.stopPropagation();
});
The above code will not work in IE8 and older since addEventListener and stopPropagation were first introduced in IE9.

can't click a link after event.preventDefault

Question:
At a project(phonegap at android), I listen the touch event as MDN guide:
document.addEventListener("touchstart", handleStart, false);
function handleStart(evt){
evt.preventDefault();
.......
}
But after that, the links can't response to click event any more.
Because you basically took away the "default behavior" of the document. Is there a reason why you have that in your code. You are adding it to the whole document.
Don't put the addEventListener on your whole document, put it on an element within the document.
evt.preventDefault(); removes the events default behaviour. If you click a button which default action is to propagate the link, the preventDefault(); will prevent this from happening.

How attach document.click event without touching some element?

I need to click on a document to call some function, but the problem is that when I click on some element that want it doesnt react, so the code:
<body>
<div class="some_element">
some element
</div>
</body>
and js:
$(document).click(function(){
//something to happen
})
and now if I click on the div with class="some_element" the document.click event will be called, but I need to call that event ONLY when I click on the document; or it is possible the make this element an exception?
More detailed:
$('#forma').click(function(e){
e.stopPropagation();
$('#assignment_type_list').slideUp();
})
Lets say #forma - its a parent element of those element, so when I click on the page I want to slideUp someElement and:
$('#assignment_type_select, #assignment_type_label').click(function(){
$('#assignment_type_list').slideToggle();
})
this is the elements when they are clicked the other element is toggled, but the problem is that when I click on this elements the $('#forma').click - also executes, because its parent and the e.stopPropagation() - doesn't help.
All this stopPropagation stuff is right, though this'll cause your script to throw errors on older versions of a certain browser. Guess which one? a cross-browser way:
$('#elem').click(function(e)
{
e = e || window.event;//IE doesn't pass the event object as standard to the handler
//event would normally work, but if you declared some event variable in the current scope
//all falls to pieces, so this e || window.event; thing is to be preferred (IMO)
if (e.stopPropagation)//check if method exists
{
e.stopPropagation();
return;
}
e.cancelBubble = true;//for IE
});
However, you wanted to check if the element that was actually clicked, is the one you need. The problem with that is, that the way the event is passed through the DOM. In W3C browsers the event is first passed to the document, and then clambers down to the element that was actually clicked (propagates through the dom). By contrast IE dispatches its events on the element itself, and then sends it up to the document (except for the change event triggered by select elements... to add insult to injury). What this effectively means is that a click event that is registered in to body element in W3C browsers might be on its way to a checkbox of sorts, or it could be a click inside an empty div. Again, in IE, when a click event reaches the body tag, it could have been dispatched too any element on the page. So it may prove useful in your case to google: event delegation, or turn to jQuery's .delegate() method.
Or check the event object to see if the event is allowed to propagate through or not:
var target = e.target || e.srcElement;//target now holds a reference to the clicked element
The property names neatly show the difference between the bubbling model and the propagating one: in the first case (srcElement), the event is coming from a source element in the dom. In the W3C propagating model, the event is cought while it's headed for a target element somewhere in the dom. Look at it like a heat-seeking missile (w3c) versus a shower of debris after the target was shot down (IE, always the destructive one, and in this case often to late to respond to the events, and therefore to late to handle them:P)
One way to do it is to check for the event's target.
$('html').click(function(event){
if (event.target != this){
}else{
//do stuff
}
});
Here's a working fiddle
Elements on the document are part of the document, so if you click "some_element" in the document, it is obvious that event registered on document will be fired/triggered. If you dont want to execute code which was for "document" then first get the element OR "event source" which originates this event, and check if it was "some_element" in your question above.

Categories