jquery document level onmousedown gets called before element's click handlers - javascript

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.

Related

Can mouseenter and click event exist together?

I am wondering if mouseenter and click event can exist together and they can both exist to TRUE when checked with:
if ((evt.type === 'mouseenter') && (evt.type === 'click'))
It is because when I mouse over the link, the mouseenter triggers (set to TRUE) and even when I clicked on it, the hover is still shown. Probably they could exist together but I'm no expert on this.
If someone can give insights, I would appreciate it a lot.
Also how can I trigger the click event during the mouseenter event?
The mouseenter event fires when the mouse enters the control. The click event fires when the mouse is clicked. They are two separate events which call two separate event handlers. If you click just as the mouse enters the element they will be called within a short timespan of one another but they are still two distinct events.
It is also important that you differentiate between the mouseenter and the mouseover events. mouseenter fires when the mouse physically enters an element, whereas mouseover fires continually while the mouse remains over an element.
While you cannot trigger the click event per se, you can call the same function that is called by the click event handler. For example if you have this:
var myfunc = function (e) { ... }
document.getElementById("id").onclick = myfunc;
Then you could simply call myfunc directly and you would get the same result as if the mouse was clicked.
They can 100% exist together, and this is a great question with no good answer... When you're on a mobile device, a mouseenter event will be thrown on tap... If you are also detecting onclick as well as mouseenter, then there will be a discrepancy between mobile devices and desktop machines.
It's kind of hard to solve such a small issue at the moment.
const x = document.getElementById('some_node')
x.onclick=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for both desktop and mobile
}
x.onmouseenter=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for mobile only (but will
//have already been triggered on desktop when cursor entered node)
}
The only workaround I came up for this, and I think it's pretty clever, is using a eventlistener for taps/touches. The order/priority that these events are fired goes: touch > mouseenter > click.
Since the touch event is fired first, you can add a touch event listener (which will only register on a mobile device), and change a variable that prevents the mouseenter event from being triggered (which is the logic that would generally be conflicting with the onclick logic)... like this:
let isMobile = false
x.addEventListener('touchstart',(e)=>{
isMobile = true
}, false);
Then your mouseenter would need to look like this:
x.onmouseenter=(e)=>{
e.stopPropagation()
if(!isMobile){
// this logic will no longer cause a conflict between desktop and mobile
}
}
they can exist on the same object, think a button with a hover state and then a click action. The click event, though will only read the click event since the enter event actually occurred earlier.
You can create a var like mouseIsOverand set it to true when the enter event fires. I can be safely assumed, though that if a click happens the mouse is over the same target.
The two events may happen at the same time, but they will still be processed on after the other. So the if you posted will never evaluate to true.
If you look at your code again you can see that it doesn't make sense. How can something be X and Y at the same time? It can't.
for the first question i think u got an answer....
however, for Also how can I trigger the click event during the mouseenter event?
u can use trigger() function..
http://jsfiddle.net/PDhBW/2/
if u want to read more about trigger
here is the link
http://api.jquery.com/trigger/
With Jquery event delegation, You can use binding multiple events at once
$('#IdElement').on('mouseenter click', function () {
//Your Code
});
http://jqfundamentals.com/chapter/events

Determining whether focus was received as result of a click event

I have an <input> element that can either have the focus set via code, or as the result of a mouse click.
If the user clicks on the input, then the click event handler will fire - all well and good. If the element receives the focus via some other way (e.g. via code) then I want to manually trigger the click event so that the handler will also fire.
I could do this:
$elem = $('input');
$elem
.on('focus', function() { $(this).trigger('click') })
.on('click', function() { alert('Clicked!') });
However, this will result in click handler being fired twice; once for the click event and once for the focus event.
Is there any way to selectively trigger the click handler only if the focus was not received as the result of a click event?
UPDATE
This is a very simplified version of my problem, so I can't do things like bind both handlers to the focus event etc. I'm trying to merge two third-party pieces of code.
The .trigger() function adds a property isTrigger in the event object to identify that the event was triggered by its usage. Although, it is not documented the property is still present in jQuery 1.8.3 but it seems to only be used internally.
Anyways, you can make use of the extraParameters parameter to add a custom property to the event object. For instance,
$(this).trigger('click', {
isTrigger: true
});
It will keep the compatibility with isTrigger even if it is gone in a future release.
After doing some more research it appears that there is no way of guaranteeing which event will fire first: click or focus. (There doesn't seem to be a standard that dictates the order of events.)
This means that when the focus event fires there's no way to determine if a click event will or will not be triggered by the browser shortly afterwards.
I managed to solve the issue by using setTimeout() to run a test about 100ms after the focus event fired to check if the click event had fired. The third-party code that I was using (bound to the click event) added an extra class to the <input>, so I was able to check for that.
You can tap into the mousedown event which fires before the focus event. When you click a focusable object the order of events is as follows... mousedown, focus, mouseup, click.
You could set a flag in the mousedown event and then check for it in the focus event to see if the focus came from a mouse click. Obviously make sure to clear the flag in the focus event handler. Every application is different, but tapping into the mousedown event allows you to figure out a solution.
Here is a JSFiddle demonstrating the order of events... http://jsfiddle.net/ek7v7/
$elem = $('input');
$elem
.on('focus', function() { alert("Focused!") })
Focus can be fired by focusing the input by using tab, clicking it, or by using .focus()
Is there a reason for on('click', ...)?

Jquery focusout on div

I have two divs, one called "mainDesign" and a box called "div1".
When "div1" is clicked, focusin is called and the border-color changes.
"div1" can only focusout if "mainDesign" is clicked.
The script works but "mainDesign" needs to be clicked twice in order for it to work, after it has focused out, the script works perfectly.
Any ideas?
Code: http://jsfiddle.net/v3DWf/14/
Thanks.
Rewrote using mousedown and stopPropagation(): http://jsfiddle.net/patrickmarabeas/v3DWf/20/
Haha, looks like Royce Feng beat me to it.
I removed focusout(), as it seems to be an unnecessary step...
Is this acceptable?: http://jsfiddle.net/patrickmarabeas/v3DWf/15/
EDIT: switched the functions around, seems to work as intended now: http://jsfiddle.net/patrickmarabeas/v3DWf/17/
You can switch to using .mousedown() and stopping propagation in the inner one.
http://jsfiddle.net/v3DWf/18/
Try this:
$("#div1").focusin(function() {
$(this).css("border-color","#ff9900");
});
$("#mainDesign").mousedown(function(){
setTimeout(function(){
if (!$("#div1").is(":focus"))
$("#div1").css("border-color","#999999");
}, 100);
});
The timeout is necessary because the mousedown will fire before the div is blurred.
Well the problem is that you've nested the .mousedown() event within the .focusout() event.
So what is happening here is that when the focusout event is triggered, you are then attaching the .mousedown event to the mainDesign div. Let me re-iterate that again, the .mousedown event will NOT be attached until the focusout event has triggered.
Then once the .mousedown event is attached, the next time you mousedown in the mainDesign div, the event will fire which is why it is currently taking you two clicks.
So the easiest solution is to simply get rid of the .focusout event.

What's the cross-browser way to capture all single clicks on a button?

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.

Assign click event inside click event

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.

Categories

Resources