Javascript: Global Element Focus Listener - javascript

I am trying to set a listener that listens for all focus events. In particular I am trying to listen for anytime an input or textbox gains focus. Per some research, the widely accepted way to achieve this is like this:
document.body.onfocus = function(event) {
//Check the event.target for input/textbox
//Do something
};
But the document.body.onfocus doesn't seem to fire, ever. I thought it might be because the document doesn't actually ever receive focus so I tried:
document.body.focus();
To initially "set" the focus, but this doesn't work either.
Any ideas on how I can listen to a focus event on all inputs/textboxes without actually setting the event directly on the element itself? Vanilla javascript only please, I am not using a framework.
Per the accepted answer here is some working code:
var focusHandler = function(event) {
var type = event.target.nodeName.toLowerCase();
if(type == 'input' || type == 'textarea') {
//Do something
}
};
document.body.addEventListener('focus', focusHandler, true); //Non-IE
document.body.onfocusin = focusHandler; //IE

As some events (focus, blur, change) do not bubble up, I would recommend you to try Event Capturing instead. First of all onfocus will not work for this, so you have to use addEventListener where you are able to specifiy the used delegation mode in the third argument. Look at MDN for the use of addEventListener.
And take a look at this article for further information about delegating the focus event up.

The focus event doesn't bubble from elements up to their ancestor elements, so you can't use event delegation (hooking it on body and seeing it for all descendants of body) to detect it.
There's a newer event, focusin (a Microsoft innovation, now also available in other browsers), which does bubble, so that may work for you depending on which browsers you want to support.

Related

efficient way to dynamically attach blur/focusout event to existing and any new input fields [duplicate]

I'm writing a form validation script and would like to validate a given field when its onblur event fires. I would also like to use event bubbling so i don't have to attach an onblur event to each individual form field. Unfortunately, the onblur event doesn't bubble. Just wondering if anyone knows of an elegant solution that can produce the same effect.
You're going to need to use event capturing (as opposed to bubbling) for standards-compliant browsers and focusout for IE:
if (myForm.addEventListener) {
// Standards browsers can use event Capturing. NOTE: capturing
// is triggered by virtue of setting the last parameter to true
myForm.addEventListener('blur', validationFunction, true);
}
else {
// IE can use its proprietary focusout event, which
// bubbles in the way you wish blur to:
myForm.onfocusout = validationFunction;
}
// And of course detect the element that blurred in your handler:
function validationFunction(e) {
var target = e ? e.target : window.event.srcElement;
// ...
}
See http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html for the juicy details
use 'Focusout' event as it has Bubble up effect..thanks.
ppk has a technique for this, including the necessary workarounds for IE: http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
aa, you can simply add the onblur event on the form, and will call the validation every time you change focus on any of the elements inside it

Focus and blur jQuery events not bubbling

With the following html structure:
<div>
<form><span><input></span></form>
</div>
<p>
and the following jquery code:
$('form').on("focus", function(event) {
$("p").append("focus no delegation<br>");
})
Why doesn't the focus event ever reach my event handler? Binding the event with a selector parameter works fine:
$('form').on("focus", "input", function(event) {
$("p").append("focus delegation<br>");
})
Event the next snippet works so the focus event does in fact bubble...
$('form').on("focus", "span", function(event) {
$("p").append("focus delegation<br>");
})
Both forms work with click and change events:
$('form').on("click", function(event) {
$("p").append("click no delegation<br>");
})
$('form').on("click", "input", function(event) {
$("p").append("click delegation<br>");
})
The only note I found about the focus event's bubbling is relative to older jQuery versions which I don't use. See it in action here
edit 1
Well this is confusing... According to jQuery's focus doc:
The focus event does not bubble in Internet Explorer. Therefore, scripts that rely on event delegation with the focus event will not work consistently across browsers. As of version 1.4.2, however, jQuery works around this limitation by mapping focus to the focusin event in its event delegation methods, .live() and .delegate().
And according to jQuery's focusin doc:
The focusin event is sent to an element when it, or any element inside of it, gains focus. This is distinct from the focus event in that it supports detecting the focus event on parent elements (in other words, it supports event bubbling).
Is it too late for me or does one contradict the other?
As Ohgodwhy pointed out, using focusin instead of focus does work.
However, I can't understand how the following code can work if the "focus" event does not bubble:
$('form').on("focus", "span", function(event) {
$("p").append("focus delegation<br>");
})
If a span child of the form receives the "focus" event, it means that the event bubbled from the input to the span. Even this works!
$('div').on("focus", "form", function(event) {
$("p").append("focus delegation<br>");
})
So... using "focusin" does fix the problem, but I'm not fully satisfied by this workaround. If anybody has a better answer, I'll happily accept it.
Yes, it appears the jQuery docs are misleading. I believe the documentation on focus neglected to mention that this was for the elements that aren't involved in user input (#Ohgodwhy listed them above in your question's comments).
I imagine it has something to do with the browser's need to trap the cursor in the input element that has focus, so that it can accept input from the keyboard. In other words, if jQuery allowed it to bubble, then you would never be given the chance to type in the input field.
Either way you'll never get a form to accept a focus event unless you first put a tabindex on it: http://jsfiddle.net/qxLqP/ but if an input based field gets focus first, it will never bubble. By default, the form element doesn't have a tabindex, and you can't set focus to something that doesn't have a tabindex.
I'd just accept #Ohgodwhy's solution of using focusin and then go let the jQuery team know about their confusing documentation.
Jquery has a cross browser function which takes care of focus delegations.
Chrome,safari and opera support an event called "DOMFocusIn" which actually delegates.
IE supports an event "focusin" for delegating focus.
Firefox supports "focus" only on capturing phase and not bubbling phase.
jQuery made a cross browser event which is "focus" which actually delegates.
I hope this answers all your doubts.

Javascript manually firing .onchange() event

I have an input field I want to assign a new value and fire an .onchange() event. I did the following:
document.getElementById("range").value='500';
document.getElementById("range").onchange();
Where range is my input Id.
I get the following error:
Uncaught TypeError: Cannot read property 'target' of undefined
Is there a way to define the 'target'?
Thank you
Try using fireEvent or dispatchEvent (depending on browser) to raise the event:
document.getElementById("range").value='500';
if (document.getElementById("range").fireEvent) {
document.getElementById("range").fireEvent("onclick");
} else if (document.getElementById("range").dispatchEvent) {
var clickevent=document.createEvent("MouseEvents");
clickevent.initEvent("click", true, true);
document.getElementById("range").dispatchEvent(clickevent);
}
The error about target is because there's code in the event handler that's trying to read the target property of the Event object associated with the change event. You could try passing in an faux-Event to fool it:
var range= document.getElementById('range');
range.onchange({target: range});
or, if you can, change the handler code to use this instead of event.target. Unless you are using delegation (catching change events on child object from a parent, something that is troublesome for change events because IE doesn't ‘bubble’ them), the target of the change event is always going to be the element the event handler was registered on, making event.target redundant.
If the event handler uses more properties of Event than just target you would need to fake more, or go for the ‘real’ browser interface to dispatching events. This will also be necessary if event listeners might be in use (addEventListener, or attachEvent in IE) as they won't be visible on the direct onchange property. This is browser-dependent (fireEvent for IE, dispatchEvent for standards) and not available on older or more obscure browsers.
from : http://www.mail-archive.com/jquery-en#googlegroups.com/msg44887.html
Sometimes it's needed to create an
event programmatically. (Which is
different from running an event
function (triggering)
This can be done by the following fire
code
> var el=document.getElementById("ID1")
>
> fire(el,'change')
>
>
> function fire(evttype) {
> if (document.createEvent) {
> var evt = document.createEvent('HTMLEvents');
> evt.initEvent( evttype, false, false);
> el.dispatchEvent(evt);
> } else if (document.createEventObject) {
> el.fireEvent('on' + evttype);
> } } looks like this trick is not yet in jQuery, perhaps for a
> reason?
Generally, your code should work fine. There might be something else that's issuing the problem, though.
Where do you run those two lines?
Are you sure that the element with the
range id is loaded by the time you
run the code (e.g. you run it in
document.ready).
Are you sure that
you only have one element with id
range on the page?
What is your onchange() function doing (could be
helpful to post it here)?
Apart from that, I would recommend using jQuery (if possible):
$('#range').trigger('change');
or just
$('#range').change();
http://api.jquery.com/change/
But as I mentioned, your case should work fine too: http://jehiah.cz/a/firing-javascript-events-properly
This seems to work for me (see this fiddle). Do you have any other code that may be the problem? How did you define your onchange handler?
Are you calling e.target in your onchange handler? I suspect this may be the issue... since you are doing the change programmatically, there is no corresponding window event.

How to detect all change/click events of HTML select that still has focus?

How can I reliably detect all events that cause the the value of an HTML select to change, while that element still has the focus?
For regular mouse input, either the click or change event works fine. For keyboard input (and for mouse input using the scroll wheel), however, the change event doesn't fire until focus is lost. I get around this by using the keyup event for keyboard changes (and ignoring the mouse wheel problem) but find my code is littered with a lot of stuff like this:
$(".my-select").keyup(handleSelect).change(handleSelect);
function handleSelect() {
var $this = $(this);
// don't process keyup events that don't result in change
if ($this.data('old-val') == $this.val()) { return; }
$this.data('old-val', $this.val());
// ... other stuff ...
}
Is there a simpler pattern/recipe that solves this problem (jQuery or straight JavaScript)?
"change" doesn't fire until the element loses focus, by design. What you're doing may be the only way to solve this. You can also look at selectedIndex as well as value.
As Diodeus said, the change event is fired when the element loses focus. But you could check if the pressed key is the enter key and then call your function. And I think hardly anybody uses the mouse wheel to change the value of a select box...

Event bubbling and the onblur event

I'm writing a form validation script and would like to validate a given field when its onblur event fires. I would also like to use event bubbling so i don't have to attach an onblur event to each individual form field. Unfortunately, the onblur event doesn't bubble. Just wondering if anyone knows of an elegant solution that can produce the same effect.
You're going to need to use event capturing (as opposed to bubbling) for standards-compliant browsers and focusout for IE:
if (myForm.addEventListener) {
// Standards browsers can use event Capturing. NOTE: capturing
// is triggered by virtue of setting the last parameter to true
myForm.addEventListener('blur', validationFunction, true);
}
else {
// IE can use its proprietary focusout event, which
// bubbles in the way you wish blur to:
myForm.onfocusout = validationFunction;
}
// And of course detect the element that blurred in your handler:
function validationFunction(e) {
var target = e ? e.target : window.event.srcElement;
// ...
}
See http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html for the juicy details
use 'Focusout' event as it has Bubble up effect..thanks.
ppk has a technique for this, including the necessary workarounds for IE: http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
aa, you can simply add the onblur event on the form, and will call the validation every time you change focus on any of the elements inside it

Categories

Resources