I have a couple of questions regarding events attached to DOM nodes. Consider the following:
http://jsfiddle.net/hXq6r/15/
Basic:
[1?] What level is the [I] (class="fixed") dom node? What level is the [II] class="container"> dom node?
[2?] How do you describe the relationship between the objects mentioned in 1? Ancestors are siblings?
[3?] When clicking the .fixed - why is the hyperlink event not triggered?
Problem:
All runs as expected. Now running this code in the Android WebView causes the problem: The click event is fired first on #button and then again on the hyperlink. I am running phonegap 1.4.1 I have no event handler attached to the hyperlink, it is just the default hyperlink event.
[4?] How is the default hyperlink event named? Click?
Advanced:
[5?] Which of the elements fires the click event first? Does it depend on the 1. level in the dom?
[6?] It seems that [I] fires first.
[7?] How can I stop the click event on [II] from firing if [I] fired previously? I just set a variable to check. Is this the best solution?
[8?] Event propagation - I assume this is of no use for this example, because we are looking at children, no ancestors. Should I delegate the event on a higher level?
Thanks : ). Hopefully this helps me with grasping the whole event basics.
Useful:
http://www.quirksmode.org/js/introevents.html
http://www.quirksmode.org/js/events_order.html
Related
I've written a bookmarklet that creates a Canvas with an event listener tracking mouse clicks that covers the whole page. The problem is that some sites have event listeners on the body of the page that have useCapture set to true. This blocks my Canvas from registering clicks.
I've researched and tried everything I could think of to remove the event listeners on the body element, but it seems that it is impossible to mess with the event listeners of the body. Does anyone have any ideas?
Side note: please don't mark this as a duplicate. None of the other posts on removing event listeners that I have seen are asking the same thing. I am not trying to remove an event listener that I created myself -- I am trying to remove an event listener that was created through code that I cannot modify.
Turns out this isn't possible. Unless somebody suggests another solution, there is no known way to access event listeners attached to the body of a webpage without pointers to those event listeners.
I have had this question in my mind for a while after reading many tutorials and posts on SO, none have been able to give me the mental model needed to get past this block.
Here is an excerpt from a terrific blog post about the Browser Events:
When we click the anchor tag, the DOM calculates the Capture Phase path, firing all the Capture Phase event handlers of the root document, body, div and anchor tags (in that order), and then it turns around and fires all of the Bubble Phase event handlers in the reverse order of the Capture Phase.
Here is the snippet of code described in the quote:
<html>
<head>
</head>
<body>
<div id="myDiv">
<a id="myAnchor"
href="http://bitovi.com/">bitovi!
</a>
</div>
</body>
</html>
Here is what I don't understand. Many explanations talk about the Capture and Bubble phases as walking down and up the DOM, which I understand. I don't understand how "all" the events are fired while walking down the tree in the capture phase and then all the bubble events are fired going up the tree. What is "all" a reference to? Is it all the events on the page? Are they fired "silently" and since they aren't where the actual click event occurred they don't execute, the only event actually fired is the element that was clicked, the rest of the events are just stored for some reason?
Later in the blog post, this other explanation also confuses me and is related to my misunderstanding about the reference to "all the events":
This is describing what happens during the Execution of the Capture Phase Events:
Now, we loop through all of the elements that we just collected (and
flipped around). A few things we need to do here:
We need to check if event.stopPropagation() was called by one of the event handlers fired (see the last step of this bulleted list). If it
was, just break out of this loop – we don’t need to iterate through
the rest of the list.
Next, we check to see if there were any Capture Phase event handlers set for the DOM node currently being evaluated.
Finally, loop through all of the handlers we collected and execute them in the context of the node currently being evaluated.
I'm confused by the last two bullet points. "Check if any Capture Phase event handlers set for the DOM node currently being evaluated". I generally understand how the event handlers are set with the addEventListener method. Here is where the confusion is:
"Loop through all of the handlers that were collected and execute them in the context of the node currently being evaluated".
Are all the handlers on the page collected and executed? If the event had the stop.prop event or did was not set on the dom node the event was triggered on, will the event not fire?
Sorry if this question is confusing, I will try to clarify anything that does not make sense. Thanks!
Not all the events, all the event handlers¹. There's only one event fired in the description, a single click event. That event is passed to each event listener attached to the elements identified in the capture/bubble chain, unless it is stopped from doing so by stopPropagation() (or stopImmediatePropagation()).
¹ Pedantically, they are event listeners. Event handlers "act as non-capture event listeners for the object on which they are specified."
I am writing a HTML editor, anyone can plug this plugin into their site and make use of it.
Plugin Usage
$(".editable").htmleditor();
Onclick on this elements I will change the element into contenteditable and my editor menu will be opened near the element like aloha editor.
Problem
Scenario 1
<div class='editable' onclick='loadUrl('https://facebook.com')'>
</div>
Scenario 2
<div class='editable' id='openNewWindow'></div>
<script>
$("#openNewWindow").click(function(e){
e.preventDefault();
e.stopPropagation();
});
</script>
Aforementioned scenarios I won't receive the event. It makes my plugin not reliable. I tried couple of solutions.
Solutions I tried
Removed all elements in a body and reinserted into it again to remove attached event handlers. It works but the UI is distorted while inserting in some sites.
Added onclick='return false' attribute in all elements. It works for some elements only.
How to unbind all attached event handlers and prevent the default event of an element?
In Scenario 1, the user of your plugin has both made an element editable, and also made clicking on it navigate away from the current page. That doesn't make much sense, but it's their business. In this situation they can't realistically expect your plugin to run.
In Scenario 2, you need to process the click event before it's handled elsewhere. Removing or suppressing existing handlers is not a good idea: it may make other parts of the page fail, and is annoying to your users in any case.
Instead, you can make your handler run in the event capture phase like this:
editableElement.addEventLister("click", myHandler, true); // note the "true"
Now your handler will run before all handlers added using JQuery (and most handlers that people add via any means), which run in the event bubble phase. Note that this technique only works in modern browsers (i.e., not IE < 9).
For reference: What is event bubbling and capturing?
I just finished a pretty intense debugging session where my cucumber test code would work using webkit but wouldn't work using selenium. The problem was solved by being very specific about the exact DOM element that was clicked. I needed to specify clicking a deeply nested <span> element. This brought up a question for which I'm not sure how to answer:
How do I know what element, initially, received an event?
I've read a bit about event bubbling, so even if my element's event handler fires, it doesn't mean that it was the initial element to receive the event. I don't understand why Chrome was able to accept a click event that was propagated down to the correct element that fired off my handler, but Firefox didn't propagate the event down.
This question on debugging events doesn't quite capture my question, because in this case I didn't know what element to examine. I basically guessed correctly. I'd love a more methodical process to use to debug. Bonus points for helping me understand better the JS event bubbling/propagation model.
It's target property of the event object.
domElement.addEventListener('click', function(e){
console.log(e.target);
});
I have a div element which has a bunch of event handlers attached to it by jQuery. 2 of these are click events, and I am trying to remove a specific one. I know that you can do:
jQuery("SELECTOR").off("click.NAMESPACE");
to only remove a specific click event with the given namespace. Hence, I used:
jQuery._data(HTML_ELEMENT, 'events');
to find out the namespace of the click event I want to remove, but it turns out to be empty. Is there a way to still achieve what I want? Thanks in advance.
Some more details:
The element has:
mouseover event
mouseout event
focus event
blur evet
keydown event
click event with namespace nspaceA
click event with no namespace
Basically, number 7 does a scroll on the page and I want to get rid of it. The problem is that these events are added from an external file and they use some variables that I don't have access to. Hence, I cannot remove all click events and add them back again (if that makes sense).