Javascript event handler on body but not on input - javascript

I have the following event handler
document.addEventListener('keydown', handleBodyKeyDown, false);
HOW DO i prevent it from occurring when inside a input box

Within your handleBodyKeyDown function, check if
event.target.tagName.toUpperCase() == 'INPUT'
(or 'TEXTAREA').
Note: For older versions of IE, use event.srcElement.tagName.
Like so:
document.addEventListener('keydown', handleBodyKeyDown, false);
function handleBodyKeyDown(event)
{
var e = event || window.event,
target = e.target || e.srcElement;
if (target.tagName.toUpperCase() == 'INPUT') return;
// Now continue with your function
}
P.S. Why are you using addEventListener if you have jQuery on the page? In jQuery, all of this gets sorted out for you:
$(document).on('keydown', ':not(input)', function(e)
{
// Your code goes here...
});

In your handleBodyKeyDown method, check to see if the event originated on an input element:
function handleBodyKeyDown(event) {
if (event.target.tagName.toUpperCase() === 'INPUT') {
return; // do nothing
}
// do the rest of your code
}
Note that the toUpperCase call is necessary because the conditions that determine the case of the tagName property are quite complicated and sometimes all but uncontrollable.
See event.target at MDN.

If you are using jQuery you can try this which uses is() method to test the target element is input then do nothing.
function handleBodyKeyDown(event) {
if ($(event.target).is("input")) {
return;
}
else{
//Do your stuff here
}
}

This worked for me:
const fromInput = event => event.srcElement instanceof HTMLInputElement;
function handleBodyKeyDown(event) {
if(fromInput(event))
return;
// do your magic here
}

You could do something like:
handleBodyKeyDown = function(e) {
var e = e || window.event
if (e.target.tagName != "INPUT") {
// handle this since it isn't input
}
}

Sometimes (as to me) it is better not to prevent it to occur, but to ignore in the event cases, when it occured in the input. It's looks like this is also your case as well.
Just inspect evt.target || evt.srcElement property (modern frameworks do this normalization work for you, so, most probably this will be called target) whether it's input or not. If not, just ignore.

QuirksMode tells you how to get an event's target. You can check that it is not an input:
function doSomething(e) {
var targ;
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
if( targ.tagName != "INPUT" ) {
//Perform your action here
}
}
Your question is tagged jQuery, in which case you can just test event.target as the framework normalizes this for you.
$(document).bind("keydown", function (event) {
if(event.target.tagName != "INPUT") {
//Do something
}
});

HandleBodyKeyDown function will be invoked in any case. You can not prevent its call on the method of recording as you indicated. You can only add a logic for checking if this an 'input' and return. Additionaly (if needed) you can prevent it from bubble up:
function handleBodyKeyDown(ev) {
ev=ev||event;
var sender=ev.target||ev.srcElement;
if(sender.tagName.toLowerCase()==="input") {
if(ev.stopPropagation)ev.stopPropagation();
else ev.cancelBubble=true; // for IE8 or less
return true; // do not prevent event from default action
}
// your code for global keydown
}

If you're using Prototype (which you have tagged but you also have two other frameworks tagged) then the event can be registered and filtered in one like this:
document.on('keydown', ':not(input)', handleBodyKeyDown);

Related

Detect focus on an input (onfocusin) even id the element does not exists in the dom yet with vanilla (plain) javascript

I have the following:
document.querySelectorAll("input[type='text']").forEach((element) => {
element.addEventListener('onfocusin', () => {
alert("was focused!!!");
});
});
The problem with these is that only works when the element exists. If some element is added to the dom after this code is called, it will not be added any event listener.
How can I detect the onfocusin event even if the element does not exist yet?
Put the event listener on a parent element that contains all (future) inputs (for example, the document itself). The event will "bubble up" from the input. Inside the handler you will need to check if the target is actually the element you want:
document.addEventListener('focusin', (e) => {
const target = e.target;
if (target.tagName == "INPUT" && target.type == "text") {
alert("was focused!!!");
}
});
MutationObserver is supported by most modern browsers, you can hook the dom changed event therein
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return;
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
obs.observe( obj, { childList:true, subtree:true });
}
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false); //<----------****
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
You can add your own logic in DOMNodeInserted() function:
Do you have access to jQuery or does it have to be plain Javascript?
In case you can use jQuery you can do:
$(document).on("focusin","input[type='text']",function(event) {
alert('element was focused', {event:event});
// let element = $(event.currentTarget);
});
See RoToRa's answer for plain JS
Angular/Typescript version
Based on the #RoToRa's answer and because I want to use this in an angular/typescript application, here how to use the #RotoRa's code in typescript:
document.addEventListener('focusin', (event: Event) => {
const target: HTMLElement = event.target as HTMLElement;
if (target instanceof HTMLInputElement && target.type === 'text') {
console.log("element was focused)
}
});

onkeydown event variable breaking the EventListener code

I have the following Javascript code:
var field = document.createElement("INPUT");
field.type = "text";
field.addEventListener("blur", function() {
// stuff that works
(e ? e : window.event).stopPropagation();
return false;
};
field.addEventListener("keydown", function() {
alert("1");
if (e) {
alert("2");
} else {
alert("3");
e = window.event;
}
alert("4");
if (e.keyCode === 13) {
this.blur();
}
return true;
}
The input field is not inside a form. Pressing enter or going out of focus is meant to submit the field value to the server (existing code I can't change). The onblur event works but the onkeydown event is not. alert("1") is executed exactly but that's all. Nothing else happened.
I have tried experimenting around and my guess is that the mere existence of e is breaking the code. I have no idea how: don't all event listeners pass an e parameter to the function being called? What's going on here? How can I resolve this?
No jQuery please, it's not available.
You are not accepting an e parameter.
In your working event, you're using e if it exists (which it wont), or falling back to window.event if it doesn't:
(e ? e : window.event)
Similar checks do not exist in the broken event listener.
Make sure you accept a parameter named e:
field.addEventListener("keydown", function(e) {
... and it will be available in your code.

Chrome (maybe Safari?) fires "blur" twice on input fields when browser loses focus

Here is an interesting jsfiddle.
In Firefox:
Run the fiddle
Click in text input
Click somewhere else. Should say "1 blurs".
Click in the text input again.
ALT-TAB to another window. Fiddle should now say "2 blurs".
In Chrome, at step 5, it says "3 blurs". Two separate "blur" events are fired when the whole browser loses focus. This is of interest because it means that it's not safe to assume, in a "blur" handler, that the element actually had focus just before the event was dispatched; that is, that the loss of focus — the transition from "being in focus" to "not being in focus" — is the reason for the event. When two "blur" events are generated, that condition is not satisfied during the handling of the second event, as the element is already not in focus.
So is this just a bug? Is there a way to tell that a "blur" event is bogus?
The reason it is firing twice is because of window.onblur. The window blurring triggers a blur event on all elements in that window as part of the way javascript's capturing/bubbling process. All you need to do is test the event target for being the window.
var blurCount = 0;
var isTargetWindow = false;
$(window).blur(function(e){
console.log(e.target);
isTargetWindow = true;
});
$(window).focus(function(){
isTargetWindow = false;
});
$('input').blur(function(e) {
if(!isTargetWindow){
$('div').text(++blurCount + ' blurs');
}
console.log(e.target);
});
​
http://jsfiddle.net/pDYsM/4/
This is confirmed Chrome bug. See the Chromium Issue Tracker
The workaround is in the accepted answer.
Skip 2nd blur:
var secondBlur = false;
this.onblur = function(){
if(secondBlur)return;
secondBlur = true;
//do whatever
}
this.onfocus = function(){
secondBlur = false;
//do whatever
}
This probably isn't what you want to hear, but the only way to do it seems to be to manually track whether the element is focused or not. For example (fiddle here):
var blurCount = 0;
document.getElementsByTagName('input')[0].onblur = function(e) {
if (!e) e = window.event;
console.log('blur', e);
if (!(e.target || e.srcElement)['data-focused']) return;
(e.target || e.srcElement)['data-focused'] = false;
document.getElementsByTagName('div')[0].innerHTML = (++blurCount + ' blurs');
};
document.getElementsByTagName('input')[0].onfocus = function(e) {
if (!e) e = window.event;
console.log('focus', e);
(e.target || e.srcElement)['data-focused'] = true;
};
Interestingly, I couldn't get this to work in jQuery (fiddle here) ... I really don't use jQuery much, maybe I'm doing something wrong here?
var blurCount = 0;
$('input').blur(function(e) {
console.log('blur', e);
if (!(e.target || e.srcElement)['data-focused']) return;
(e.target || e.srcElement)['data-focused'] = false;
$('div').innerHTML = (++blurCount + ' blurs');
});
$('input').focus(function(e) {
console.log('focus', e);
(e.target || e.srcElement)['data-focused'] = true;
});
You could also try comparing the event's target with document.activeElement. This example will ignore the alt+tab blur events, and the blur events resulting from clicking on Chrome's... chrome. This could be useful depending on the situation. If the user alt+tabs back into Chrome, it's as if the box never lost focus (fiddle).
var blurCount = 0;
document.getElementsByTagName('input')[0].onblur = function(e) {
if (!e) e = window.event;
console.log('blur', e, document.activeElement, (e.target || e.srcElement));
if ((e.target || e.srcElement) == document.activeElement) return;
document.getElementsByTagName('div')[0].innerHTML = (++blurCount + ' blurs');
};​
​
I'm on Chrome Version 30.0.1599.101 m on Windows 7 and this issue appears to have been fixed.
I am experiencing the same and the above posts make sense as to why. In my case I just wanted to know if at least one blur event had occurred. As a result I found that just returning from my blur function solved my issue and prevented the subsequent event from firing.
function handleEditGroup(id) {
var groupLabelObject = $('#' + id);
var originalText = groupLabelObject.text();
groupLabelObject.attr('contenteditable', true)
.focus().blur(function () {
$(this).removeAttr('contenteditable');
$(this).text($(this).text().substr(0, 60));
if ($(this).text() != originalText) {
alert("Change Found");
return; //<--- Added this Return.
}
});
}
Looks like an oddity of angularjs gives a simpler solution when using ng-blur; the $event object is only defined if you pass it in:
ng-blur="onBlur($event)"
so (if you aren't using ng-blur on the window) you can check for:
$scope.onBlur = function( $event ) {
if (event != undefined) {
//this is the blur on the element
}
}

Problem with event handler

function getFieldName(e) {
e = e || window.event;
var key = e.keyCode || e.which,
target = e.target || e.srcElement;
alert(target.name);
return (key != 13);
}
I have the above function called on body tag onkeypress = getFieldName(event);
I get the name of desired field but not able to check in IE as well as FF
if(target.name == 'check') {
// works fine in FF but in IE I'm not able
// to come inside this if-block, please suggest
}
thanks
I see you've tagged this post as jQuery... If you actually use jQuery to manage the event handler then you can use e.which to find the key that was pressed and e.target to find the DOM target. It also worries about the cross-browser stuff for you.
To attach a function as an event handler, you can follow this simple example:
$(document).keypress(getFieldName);
jQuery already normalizes some event properties internally, so you can just use event.target and event.which, you don't need to check for others, like this:
$(document).keypress(getFieldName);
function getFieldName(e) {
alert(e.target.name);
if(e.which == 13) {
alert("Key pressed was enter");
} else {
alert("Key pressed was not enter");
}
}
​
You can view a quick demo here

How to get the onclick calling object?

I need to have a handler on the calling object of onclick event.
link
<script>
function click123(event) {
//i need <a> so i can manipulate it with Jquery
}
</script>
I want to do this without the use of $().click or $().live of jQuery but with the method described above.
pass in this in the inline click handler
link
or use event.target in the function (according to the W3C DOM Level 2 Event model)
function click123(event)
{
var a = event.target;
}
But of course, IE is different, so the vanilla JavaScript way of handling this is
function doSomething(e) {
var targ;
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
}
or less verbose
function doSomething(e) {
e = e || window.event;
var targ = e.target || e.srcElement || e;
if (targ.nodeType == 3) targ = targ.parentNode; // defeat Safari bug
}
where e is the event object that is passed to the function in browsers other than IE.
If you're using jQuery though, I would strongly encourage unobtrusive JavaScript and use jQuery to bind event handlers to elements.
I think the best way is to use currentTarget property instead of target property.
The currentTarget read-only property of the Event interface identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed to Event.target, which identifies the element on which the event occurred.
For example:
<span class="icon"></span> blah blah
Javascript:
a.addEventListener('click', e => {
e.currentTarget; // always returns "a" element
e.target; // may return "a" or "span"
})
The easiest way is to pass this to the click123 function or
you can also do something like this(cross-browser):
function click123(e){
e = e || window.event;
var src = e.target || e.srcElement;
//src element is the eventsource
}
http://docs.jquery.com/Events/jQuery.Event
Try with event.target
Contains the DOM element that issued
the event. This can be the element
that registered for the event or a
child of it.
The thing with your method is that you clutter your HTML with javascript. If you put your javascript in an external file you can access your HTML unobtrusive and this is much neater.
Lateron you can expand your code with addEventListener/attackEvent(IE) to prevent memory leaks.
This is without jQuery
link
window.onload = function () {
var el = document.getElementById('elementid');
el.onclick = function (e) {
var ev = e || window.event;
// here u can use this or el as the HTML node
}
}
You say you want to manipulate it with jQuery. So you can use jQuery. Than it is even better to do it like this:
// this is the window.onload startup of your JS as in my previous example. The difference is
// that you can add multiple onload functions
$(function () {
$('a#elementid').bind('click', function (e) {
// "this" points to the <a> element
// "e" points to the event object
});
});

Categories

Resources