Inside of an onclick event, I'm binding another onclick event. But when I initiate the first event, the second always executes:
var MiniMenu = {
show : function(menu_id, element){
// this doesn't have any thing to do with the problem - I think
position = $(element).offset();
$('#' + menu_id).css({
left : position.left,
top : position.top + 13
}).show();
// Why is this event called on the first click,
// even though it isn't bound at that time?
$(document).click(function(){
alert('here')
$('.mini-menu').hide();
$(document).unbind('click')
})
}
}
I'm using Adobe Air - if that helps :)
I guess because the click-event just bubbles up ;-)
Think of the following: you have a stack of event handlers assigned to the click event, probably most of them without you knowing of their existance
Your click handler <-- currently executing
...
System click handler 2 <-- already finished
System click handler 1
Now while executing, your click handler adds another listener to this event.
New click handler
Your click handler <-- currently executing
...
System click handler 2
System click handler 1
When your first click handler finishes, the click event just gets passed to the next listener in the queue (this is called bubbling), because you don't prevent the event propagation. That means that after Your click handler returns, you have the following situation:
New click handler <-- currently executing
Your click handler
...
System click handler 2
System click handler 1
This may be a bubbling issue. Is the first click event's source element something inside of your document? (or is it the document, as is the second click event handler?)
Events bubble up to the container all the way to the document. If you're handling the event on an image or something, and then setting the click event handler on something up the chain, it may be fired right afterward.
$(document).click(function(){
alert('here')
$('.mini-menu').hide();
$(document).unbind('click')
})
This binds the click to the document really, so ANY click anywhere in the document will cause this to be activated...
I would need more information to be able to isolate what you REALLY want to do with this even.
EDIT: Just to add some info, you may want to return FALSE side the event to prevent the event from propagating (bubbling) up the document and to stop. Study the event handling documentation for jQuery for more tangible results pertinent to your situation.
EDIT2: to explain, when you bind the DOCUMENT here, once the function completes, the document still has the event and then activates it at that time (after the function)... I hope I am explaining this so it makes sense.
Related
I'm new to JS, just a dumb question on event listener, I know how to add an event listener, but confused with what really it is, below is some code:
document.getElementById("myBtn").addEventListener("click", function(){
...
});
and I was reading a book which says sth like this:
event in the listing is triggered when the mouse button is clicked on the host element, and the event provides its listeners with ...
so can I say the listener in this case is the button element(with id myBtn)? or listener is a property of button element?
A listener is an event of DOM element, in this case, the click event is an event of your button myBtn that fires when a user makes a click in the primary button.
You can get more info from here
To answer your question in very simple terms:
There are three javascript constructs to look out for in this code
document.getElementById("myBtn").addEventListener("click", function(){ ... });
They are:
the event
The actual event that occurs on the page. This can be triggered by a user, another event, or can be time-triggered.
the event listener
This is an internalised javascript software construct that can be initialized by the programmer to listen for various events that occur on the page.
the event handler
This is a function created by the programmer and passed to the event listener to execute whenever an event occurs i.e. handle the event.
Interestingly, the only thing you can see explicitly in the above code is the event handler - function(){ ... }. Why? Because it is the only thing the programmer explicitly creates in the code.
So, the code can be read as -
get my button with id myBtn.
initialize an Event Listener to listen for click Events on this button and
delegate an anonymous Event Handler to execute when this event occurs.
For example we have a page with a link that has onclick event listener on it. But handler makes stopPropagation. How I can handle that click event was made, if it's not bubble to root anymore?
e.g.
document.addEventListener('click', function(e) {console.log(e);});
a.onclick = function(e) {e.stopPropagation();};
DOM event propagation works in three phases: the capture phase, the target phase and the bubble phase. Roughly, the event first works its way down to the target, reaches the target and then works its way back up.
By default, event handlers are attached in the final bubble phase. If you attach a click event listener in the first capture phase, it will run before the previous handler has had the chance to call stopPropagation.
See this question for a deeper explanation.
The simple answer is, add a third argument, true, when adding your event listener.
document.addEventListener('click', someFunction, true)
This flag (called useCapture) will call someFunction on all clicks in a document, even when the user clicked inside an element with a click handler that called event.stopPropagation.
With options
If you're already passing an object of options as the third argument, simply include capture: true in them:
document.addEventListener('click', someFunction, { capture: true, ...someMoreOptions })
Why?
Enabling the handler's useCapture mode like this means the listener listens during the earlier "capture" phase of the event (which starts at the outmost element then trickles down through children), instead of the later "bubble" phase (which starts at the innermost element and bubbles back up through ancestors, and is the one stopPropagation blocks).
Side effects
That also means that applying this setting changes the timing: your capture phase click event will occur before any click events of either type inside child or descendant elements.
For example, in the above function, if a user clicks on a button on the page, the someFunction attached to the document's capture phase will be called before any handlers attached to the button; whereas without setting use capture to true, you'd expect it to be called after.
Some code that looks like the following is firing the click event via the Enter key, but is not responding to the mouse click.
//a is an anchor element
a.addEventListener('click', function (e)
{
//Do Stuff...
});
This page demonstrates the problem. The relevant bit of code is at line 176. This is in the middle of development and currently only (sort of) works in Chrome.
Also, I just verified that it works if I use mousedown, so it's not just the case of an invisible element sitting in front of the anchor.
Any ideas?
Edit: Now that you've shown us the actual code you're using, the problem is related to the fact that the autoSuggest() function has it's own click handler and in that click handler, it is clearing the container which removes all <a> elements in the container so your link object gets destroyed (probably before your click event gets to process). So, you can get events that happen before the click (like mousedown), but after a click, the element is removed from the DOM.
If you tell us what you're trying to actually do when an auto-suggest item is clicked that is different than the default behavior of the autoSuggest() function and you point to any documentation for that function, then perhaps we could offer a better way to solve your issue.
The link may be firing and taking you off to a new page (or reloading the current page), thus preventing you from seeing the click code run. Usually when you process a click event on a link element, you need to prevent the default behavior:
//a is an anchor element
a.addEventListener('click', function (e) {
e.preventDefault();
//Do Stuff...
});
Another possibility is that you are trying to install the event handler too soon either before the DOM has been loaded or before this particular link has been created and thus no actual click event handler is attached to the DOM object. You can verify whether the event handler is even getting called by temporarily putting an alert("Click handler called"); in the event handler and see if that pops up or not.
I am using jquery 1.3.2.
I am registering two handlers as follows:
$(document).onmousedown(dochandler)
$('#element').click(elemhandler)
When I click on #element both the handlers get called. And surprisingly dochandlers gets called before elemhandler. I have tried changing the orders of above handler registration, but no use.
Both handlers are returning false to avoid event propagation.
My understanding is elemhandler should get called when #element is clicked. Since I am returning false from elemhandler, the dochandler should not be called. And even if dochandler gets called, it shouldn't get called before elemhandler.
Any idea what might be wrong here?
Thanks.
They are two separate events so returning false on one wont affect the other. The click event is fired when the mouse button is released: http://api.jquery.com/click/
dochandler is called prior elemhandler because mousedown event happens prior click event and as poswald mentioned, they are two separate events and they don't affect each other.
The click event means the mouse buttons is pressed down and released. The mouseDown is only pushed down. For example if you do drag and drop, the mouseDown event is fired, then any number of mouseMove, and finally mouseUp.
So yes, mouseDown is fired before click. And as others said they are different events so they don't affect each other.
What's the best way to execute a function exactly once every time a button is clicked, regardless of click speed and browser?
Simply binding a "click" handler works perfectly in all browsers except IE.
In IE, when the user clicks too fast, only "dblclick" fires, so the "click" handler is never executed. Other browsers trigger both events so it's not a problem for them.
The obvious solution/hack (to me at least) is to attach a dblclick handler in IE that triggers my click handler twice. Another idea is to track clicks myself with mousedown/mouseup, which seems pretty primitive and probably belongs in a framework rather than my application.
So, what's the best/usual/right way of handling this? (pure Javascript or jQuery preferred)
Depending on your situation you can use different approaches, but I would suggest using namespaced event handlers with jQuery like this:
function eventHandler(event) {
// your handler code here
doSomeMagic();
}
var element = $('#element');
element.one('click.someNameSpace', function(event){
// first we unbind all other event handlers with this namespace
element.unbind('.someNameSpace');
// then we execute our eventHandler
eventHandler();
}).one('dblclick.someNameSpace', function(event){
// If this fires first, we also unbind all event handlers
element.unbind('.someNameSpace');
// and then execute our eventHandler
eventHandler();
});
I'm not sure this will work the way you want it, but it's a start, I guess.
Mousedown and mouseup works just like the click functions, unfortunately so much that when IE omits a click because of a doubleclick it will also omit the mousedown and mouseup. In any case, you can add both click and dblclick to the same object and feed the clicks through a function that sort out any click happening too close to the last.
<div onclick="clk()" ondblclick="clk()"></div>
lastclicktime=0
function clk(){
var time=new Date().getTime()
if(time>lastclicktime+50){
lastclicktime=time
//Handle click
}
}
I by the way just found out that, at least in Firefox the dblclick event is not given an event time, therefore I had to resolve to the Date method.