When a user clicks on a HTML element, it seems a number of JavaScript events other than just "click" are fired. For example, clicking on a input/text element also triggers events like focus, mousedown, mouseup, etc...
Essentially, when a human clicks on an element, what are all the events that get fired? (besides click!)
For the specific button click, there will be:
mousedown
mouseup
click
If the mouse entered a new element in the period you are looking you may also see:
mousemove
mouseover
mouseenter
mouseleave (on other element)
mouseout (on other element)
If the focus changes based on the click:
focusout (on some other element)
blur (on some other element)
focusin
focus
You can see an exact sequence of events in this jsFiddle that logs all the events: https://jsfiddle.net/jfriend00/r9c7n5j2/
If the focus is elsewhere and you click into an input tag, you will see this sequence of events (for clarity, only one mousemove event is shown, but there will likely be many):
mouseover
mouseenter
mousemove
mousedown
focus
focusin
mouseup
click
Note: focusin is not yet supported in Firefox.
Check out this bit in the w3:
Should be what you're looking for. Also MDN has a good overview of them
Related
.on("mouseenter") and .on("mouseleave"),
when console.log the event, in both cases the event.type is "mouseover"
Is that normal ? I though that for mouseenter you see event.type "mouseenter"
My problem is that javascript mouseenter event fired twice when hovering over the element.
I can see that the event.fromElement is different in both fired events.
How do I stop the bubbling ? event.stopProppagation, doesn't work
<span class="foo-wrapper">
<i class="icon-circle"></i>
</span>
$(".foo-wrapper .icon-circle").on("mouseenter", function(e){
e.stopPropagation();
cur_target = $(e.target);
$("#tooltip").css({'top': parseInt(cur_target.offset().top-116), 'left': parseInt(cur_target.offset().left-141)}).fadeIn(150);
}
When the mouse enter the .icon-circle, it fires twice.
mouseenter is not a native dom event. Its wrapping mouseover. Let me explain:
Say you have element P, which is 100x100, and that has a child element C which is 50x50.
When you first hover over P, you get both mouseover and mouseenter. When you now hover over C, the browser fires mouseout for P and mouseover for C.
But C is inside P, so you didn't 'leave' P yet- which is why mouseenter and mouseleave were made.
The library implementing the events checks the targets of the over and out events in order to determine whether to fire enter or leave.
So if its firing twice, its probably from different elements. You need to add the handler to the correct element and not to both.
You can also call event.preventDefault() and/or return false from the event handler.
In jQuery v2.1.0 it seems to work properly. Here is an example with your code http://jqversion.com/#!/jad2sKb . It seems that the mouseenter event is fired just once, and the event.type is mouseenter
If there is anything different please update the demo.
There is a textarea element which converts itself into a div when onblur event happens on that same textarea. There is also a button which has its onclick property set to function f.
If one is writing in the textarea and then clicks on a button, f is fired, but also onblur event handler is triggered. Is there some order rules in this case, or the two handler functions may fire in random order?
I created a jsfiddle here: http://jsfiddle.net/z5SEp/
The events for latest Chrome seem to be:
mousedown
blur
mouseup
click
Although I could not find any documentation to rely on, it would make sense to me that blur is fired after mousedown, but before mouseup. Mousedown causes blur, but you could leave your mouse button down for an extended period of time and still cause a blur.
The order of click events will always be 1. mousedown 2. mouseup 3. click. The blur makes sense to be after mousedown but before mouseup.
More things to keep in mind
If you trigger the button click like this: $('button').trigger('click');, then the blur event will not fire, and focus will remain on the textarea.
In this scenario, the blur will always fire first because blur is triggered as soon as the mouse button goes down elsewhere on the page. So when the mouse goes down on your button, the textarea's blur event is fired first. As the mouse comes up, the button's click event is fired.
As JQuery document says, I have converted many lines mouseover to mouseenter because it does not fire more than once.
http://api.jquery.com/mouseover/
mouseover fires when the pointer moves into the child element as well
mouseenter fires only when the pointer moves into the bound element.
Even hover event works as mouseenter and mouseleave, not as mouseover and mouseout.
It makes me wonder why there is mouseover event if mouseenter can do it all.
For me, mouseover gets fired unpredictably when you move mouse around on an element. It seems really dependent on the depth of child elements.
Is there a good use-case of mouseover and mouseout, which needs to fire multiple times?
That I know of, there is no use case for mouseover/mouseout at all. The only reason they exist is because these events are triggered by browsers because they are in the standard DOM event list. mouseenter and mouseleave are not standard events, but they are jQuery-specific constructs.
I suppose a use case would be if you wanted the event to trigger when moving the mouse over and out of the children of the element that the events are bound to. I can't think of anything specific, but at least this functionality is available. If only mouseenter/mouseleave existed, you wouldn't have a choice in the matter.
From http://code.jquery.com/jquery-1.9.1.js:
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
/* content snipped */
Speculation: the reason why the creators of jQuery created the mouseenter and mouseleave non-standard events is because their behavior works as you would expect the mouseover/mouseout events to work (i.e. without regard for descendants).
Because the event contains coordinates of cursor.
So if you need to track mouse coordinates under the target, you have to use 'mouseover'
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', ...)?
I don't understand why the jQuery blur handler isn't working in the most simple case. I'm literally creating a div 100px by 100px and setting a blur event on it, but it's not firing (JSFiddle):
<div id="test">this is a test</div>
$(document).ready(function() {
$('#test').bind('blur', function() {
alert('blur event!');
});
});
Is my understanding of blur wrong? I expect the blur event to fire when I click anywhere that is not the div...right?
According to jQuery's documentation:
In recent browsers, the domain of the event has been extended to
include all element types. An element can lose focus via keyboard
commands, such as the Tab key, or by mouse clicks elsewhere on the
page.
I've tried it on the latest Chrome and Firefox on Mac.
From the W3C DOM Events specification:
focus
The focus event occurs when an element receives focus either via a pointing device or by
tabbing navigation. This event is valid for the following elements: LABEL, INPUT, SELECT,
TEXTAREA, and BUTTON.
blur
The blur event occurs when an element loses focus either via the pointing device or by
tabbing navigation. This event is valid for the following elements: LABEL, INPUT, SELECT,
TEXTAREA, and BUTTON.
The jQuery docs state browsers extended the events to other elements, which I'm guessing means blur and focus are aliases for the more generic DOMFocusIn and DOMFocusOut events. Non-input elements aren't eligible to receive those by default though, and an element has to somehow gain focus before losing it - a blur still won't fire for every click outside the div.
This SO question mentions that giving an element a tabindex would allow that, and seems to work for me in Chrome after modifying your jsFiddle. (Albeit with a fairly ugly outline.)
As far as I knew, blur happens on inputs that had the focus, either way you say
I expect the blur event to fire when I click anywhere that is not the div...right?
Not exactly, the blur event only happens for an element that had the focus first
So in order for a blur event to occur, you would first have to give focus to the div, how is the div getting focus first?
If you are really try to determine if there was a click outside of your div, you need to attach a click handler to the document, and then check to see where your click came from.
var div_id = "#my_div";
var outsideDivClick = function (event) {
var target = event.target || event.srcElement;
var box = jQuery(div_id);
do {
if (box[0] == target) {
// Click occured inside the box, do nothing.
return;
}
target = target.parentNode;
} while (target);
}
jQuery(document).click(outsideDivClick);
Just remember that this handler will be run for EVERY click on the page. (in the past if i ha to use something like this, i attach the handler when I need it, and remove it when I no longer need to look for it)
A can't "blur" because that would involve the div having focus in the first place. Non-input elements like a and textarea can have focus, which is what jQuery's documentation refers to.
What you need is the "mouseout" or "mouseleave" event (mouseleave doesn't bubble, mouseout does), which will be fired when the cursor leaves the div. If you need to have clicks, I would attach a "click" event to the body, as well as the div and stopping the event propagation on only the div:
$("div").click(function(e) {
return false; // stop propagation
});
Or, if you're really determined, you can fake the appearance of a div with a and some CSS rules :)
If you want something to happen while you move your mouse over the box, you could use the mouseover event.