Is there a way to run a JavaScript function when a key is pressed and released?
For example, how would I run a function example() when the T key is pressed? I've seen examples of these before, but they were long and messy, and I couldn't get them to work. Would something like this just go in a <script> in the <head>?
Part 1: Where to put the scriptblock?
To capture over the entire page, like as a page-help-function (maybe you want to capture F1?) then you would put your script block in the <head> tag, inside a script. But if you want to capture a DOM element, then you have to execute the code after the DOM element occurs (because the script is interpreted as it's found, if the DOM element doesn't exist yet, the selector engine can't find it. If this doesn't make sense say something, and an article shall be found).
But here's something for you to consider: Good javascript programmer mentors today recommend all javascript be loaded at the end of the page. The only things you might want to load at the head of the document are libraries like jQuery, because those are widely cached, especially if you're using a CDN version of jQuery, as that generally tends to not impact load times.
So that answers the question of "where do I put the codeblock, in the <head>?": No. At the end.
Now, as to how to actually capture the keystroke, let's do it in three parts:
Part 2: Capturing all keyboard events on the window:
<html>
<head>
<title>blah blah</title>
<meta "woot, yay StackOverflow!">
</head>
<body>
<h1>all the headers</h1>
<div>all the divs</div>
<footer>All the ... ... footers?</footer>
<script>
/* the last example replaces this one */
function keyListener(event){
//whatever we want to do goes in this block
event = event || window.event; //capture the event, and ensure we have an event
var key = event.key || event.which || event.keyCode; //find the key that was pressed
//MDN is better at this: https://developer.mozilla.org/en-US/docs/DOM/event.which
if(key===84){ //this is for 'T'
doThing();
}
}
/* the last example replace this one */
var el = window; //we identify the element we want to target a listener on
//remember IE can't capture on the window before IE9 on keypress.
var eventName = 'keypress'; //know which one you want, this page helps you figure that out: http://www.quirksmode.org/dom/events/keys.html
//and here's another good reference page: http://unixpapa.com/js/key.html
//because you are looking to capture for things that produce a character
//you want the keypress event.
//we are looking to bind for IE or non-IE,
//so we have to test if .addEventListener is supported,
//and if not, assume we are on IE.
//If neither exists, you're screwed, but we didn't cover that in the else case.
if (el.addEventListener) {
el.addEventListener('click', keyListener, false);
} else if (el.attachEvent) {
el.attachEvent('on'+eventName, keyListener);
}
//and at this point you're done with registering the function, happy monitoring
</script>
</body>
</html>
Part 3: Capturing all keyboard events on a specific element
This line: var el = window; //we identify the element we want to target a listener on might also be var el = document.getElementByTagName('input'); or some other document selector. The example still works the same that way.
Part 4: An 'elegant' solution
var KeypressFunctions = [];
KeypressFunctions['T'.charCodeAt(0)] = function _keypressT() {
//do something specific for T
}
KeypressFunctions['t'.charCodeAt(0)] = function _keypresst() {
//do something specific for t
}
//you get the idea here
function keyListener(event){
//whatever we want to do goes in this block
event = event || window.event; //capture the event, and ensure we have an event
var key = event.key || event.which || event.keyCode; //find the key that was pressed
//MDN is better at this: https://developer.mozilla.org/en-US/docs/DOM/event.which
KeypressFunctions[key].call(); //if there's a defined function, run it, otherwise don't
//I also used .call() so you could supply some parameters if you wanted, or bind it to a specific element, but that's up to you.
}
What does all this do?
The KeypressFunctions is an array, that we can populate with various values but have them be somewhat human readable. Each index into the array is done as 'T'.charCodeAt(0) which gives the character code (event.which || event.keyCode look familiar?) for the index position into the array that we're adding a function for. So in this case our array only has two defined index-values, 84 (T) and 116 (t). We could've written that as KeypressFunctions[84] = function ... but that's less human-readable, at the expense of the human-readable is longer. Always write code for yourself first, the machine is often smarter than you give it credit for. Don't try and beat it with logic, but don't code excessive if-else blocks when you can be slightly elegant.
gah! I forgot to explain something else!
The reason for the _keypressT and _keypresst is so that when this gets called as an anonymous function, or as part of a callstack (it will, one day) then you can identify the function. This is a really handy practice to get into the habit of, making sure that all potentially anonymous functions still get "named" even though they have a proper name elsewhere. Once again, good javascript mentors suggest things that help folks ;-).
gah! I forgot to explain something else!
Notice you could just as easily do:
function doThing() //some pre-defined function before our code
var KeypressFunctions = [];
KeypressFunctions['T'.charCodeAt(0)] = doThing
KeypressFunctions['t'.charCodeAt(0)] = doThing
and then for either T or t, the doThing function is run. Notice that we just passed the name of the function and we didn't try to run the function by doThing() (this is a HUGE difference and a big hint if you're going to do this sort of thing)
I can't believe I forgot this one!
Part 5: jQuery:
Because the emphasis today is on jQuery, here's a block you can put anywhere in your app after the jQuery library has loaded (head, body, footer, whatever):
<script>
function doTheThingsOnKeypress(event){
//do things here! We've covered this before, but this time it's simplified
KeypressFunctions[event.which].call();
}
$(document).on('keypress','selector',doTheThingsOnKeypress);
// you could even pass arbitrary data to the keypress handler, if you wanted:
$(document).on('keypress','selector',{/* arbitrary object here! */},doTheThingsOnKeypress);
//this object is accessible through the event as data: event.data
</script>
If you're going to use the KeypressFunctions as from before, ensure they are actually defined before this.
Use the onkeydown event and the keyCode property (where T code is 84):
document.onkeydown = function(e){
e = e || window.event;
var key = e.which || e.keyCode;
if(key===84){
example();
}
}
I just suggest you to use addEventListener/attachEvent methods instead of the onkeydown property
EDIT:
As T.J. Crowder requested, here's the addEventListener/attachEvent usage, with a compatibility check:
var addEvent = document.addEventListener ? function(target,type,action){
if(target){
target.addEventListener(type,action,false);
}
} : function(target,type,action){
if(target){
target.attachEvent('on' + type,action,false);
}
}
addEvent(document,'keydown',function(e){
e = e || window.event;
var key = e.which || e.keyCode;
if(key===84){
example();
}
});
And for a list of the key codes, check this page
Bind a keyup/down/press event handler to the document object.
Check which key was pressed (by looking at key or keyCode on the event object
Call the function if it matches the key want you want
It doesn't matter where the script runs, the document object is (effectively) always available.
Related
I am new to JavaScript/jQuery and I've been learning how to make functions. A lot of functions have cropped up with (e) in brackets. Let me show you what I mean:
$(this).click(function(e) {
// does something
});
It always appears that the function doesn't even use the value of (e), so why is it there so often?
e is the short var reference for event object which will be passed to event handlers.
The event object essentially has lot of interesting methods and properties that can be used in the event handlers.
In the example you have posted is a click handler which is a MouseEvent
$(<element selector>).click(function(e) {
// does something
alert(e.type); //will return you click
}
DEMO - Mouse Events DEMO uses e.which and e.type
Some useful references:
http://api.jquery.com/category/events/
http://www.quirksmode.org/js/events_properties.html
http://www.javascriptkit.com/jsref/event.shtml
http://www.quirksmode.org/dom/events/index.html
http://www.w3.org/TR/DOM-Level-3-Events/#event-types-list
DISCLAIMER: This is a very late response to this particular post but as I've been reading through various responses to this question, it struck me that most of the answers use terminology that can only be understood by experienced coders. This answer is an attempt to address the original question with a novice audience in mind.
Intro
The little '(e)' thing is actually part of broader scope of something in Javascript called an event handling function. Every event handling function receives an event object. For the purpose of this discussion, think of an object as a "thing" that holds a bunch of properties (variables) and methods (functions), much like objects in other languages. The handle, the 'e' inside the little (e) thing, is like a variable that allows you to interact with the object (and I use the term variable VERY loosely).
Consider the following jQuery examples:
$("#someLink").on("click", function(e){ // My preferred method
e.preventDefault();
});
$("#someLink").click(function(e){ // Some use this method too
e.preventDefault();
});
Explanation
"#someLink" is your element selector (which HTML tag will trigger this).
"click" is an event (when the selected element is clicked).
"function(e)" is the event handling function (on event, object is created).
"e" is the object handler (object is made accessible).
"preventDefault()" is a method (function) provided by the object.
What's happening?
When a user clicks on the element with the id "#someLink" (probably an anchor tag), call an anonymous function, "function(e)", and assign the resulting object to a handler, "e". Now take that handler and call one of its methods, "e.preventDefault()", which should prevent the browser from performing the default action for that element.
Note: The handle can pretty much be named anything you want (i.e. 'function(billybob)'). The 'e' stands for 'event', which seems to be pretty standard for this type of function.
Although 'e.preventDefault()' is probably the most common use of the event handler, the object itself contains many properties and methods that can be accessed via the event handler.
Some really good information on this topic can be found at jQuery's learning site, http://learn.jquery.com. Pay special attention to the Using jQuery Core and Events sections.
e doesn't have any special meaning. It's just a convention to use e as function parameter name when the parameter is event.
It can be
$(this).click(function(loremipsumdolorsitamet) {
// does something
}
as well.
In that example, e is just a parameter for that function, but it's the event object that gets passed in through it.
The e argument is short for the event object. For example, you might want to create code for anchors that cancels the default action. To do this you would write something like:
$('a').click(function(e) {
e.preventDefault();
}
This means when an <a> tag is clicked, prevent the default action of the click event.
While you may see it often, it's not something you have to use within the function even though you have specified it as an argument.
In jQuery e short for event, the current event object. It's usually passed as a parameter for the event function to be fired.
Demo: jQuery Events
In the demo I used e
$("img").on("click dblclick mouseover mouseout",function(e){
$("h1").html("Event: " + e.type);
});
I may as well have used event
$("img").on("click dblclick mouseover mouseout",function(event){
$("h1").html("Event: " + event.type);
});
Same thing!
Programmers are lazy we use a lot of shorthand, partly it decreases our work, partly is helps with readability. Understanding that will help you understand the mentality of writing code.
Today I just wrote a post about "Why do we use the letters like “e” in e.preventDefault()?" and I think my answer will make some sense...
At first,let us see the syntax of addEventListener
Normally it will be:
target.addEventListener(type, listener[, useCapture]);
And the definition of the parameters of addEventlistener are:
type :A string representing the event type to listen out for.
listener :The object which receives a notification (an object that implements the Event interface) when an event of the specified type
occurs. This must be an object implementing the EventListener
interface, or a JavaScript function.
(From MDN)
But I think there is one thing should be remarked:
When you use Javascript function as the listener, the object that implements the Event interface(object event) will be automatically assigned to the "first parameter" of the function.So,if you use function(e) ,the object will be assigned to "e" because "e" is the only parameter of the function(definitly the first one !),then you can use e.preventDefault to prevent something....
let us try the example as below:
<p>Please click on the checkbox control.</p>
<form>
<label for="id-checkbox">Checkbox</label>
<input type="checkbox" id="id-checkbox"/>
</div>
</form>
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
//var e=3;
var v=5;
var t=e+v;
console.log(t);
e.preventDefault();
}, false);
</script>
the result will be : [object MouseEvent]5 and you will prevent the click event.
but if you remove the comment sign like :
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
var e=3;
var v=5;
var t=e+v;
console.log(t);
e.preventDefault();
}, false);
</script>
you will get : 8 and an error:"Uncaught TypeError: e.preventDefault is not a function
at HTMLInputElement. (VM409:69)".
Certainly,the click event will not be prevented this time.Because the "e" was defined again in the function.
However,if you change the code to:
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
var e=3;
var v=5;
var t=e+v;
console.log(t);
event.preventDefault();
}, false);
</script>
every thing will work propertly again...you will get 8 and the click event be prevented...
Therefore, "e" is just a parameter of your function and you need an "e" in you function() to receive the "event object" then perform e.preventDefault(). This is also the reason why you can change the "e" to any words that is not reserved by js.
It's a reference to the current event object
this will be my first stackoverflow help but I am confident that my answer will help anyone reading this.
Basically, e is just an object containing information about the EVENT which has just occured.
if it is 'click', then the object will contain about the click,
if it is 'submit', then the object will contain about the submit,
and they are typically found in addEventListener.
clickMe.addEventListener('click', e => {
console.log(e)
}
meaning, whenever I 'click' the button, it will console.log the INFOMRATION about the event that happened which is I did is to 'click' it, this will print information about the click event.
e is very useful because you can access and use the event to your very own project such as printing the location of x value... like
clickMe.addEventListener('click', e => {
console.log(e.clientX)
}
then it will print the location where you 'click' that event.. mine it returns 32
if you prefer video, please watch this
https://www.youtube.com/watch?v=_BVkOvpyRI0
video is not mine
upvoting me will truly help me since I am a student and looking for opportunity to help here. Love lots!
$(this).click(function(e) {
// does something
});
In reference to the above code
$(this) is the element which as some variable.
click is the event that needs to be performed.
the parameter e is automatically passed from js to your function which holds the value of $(this) value and can be used further in your code to do some operation.
I am trying to debug a function using Firebug, for the JavaScript getModifierState() method seems to be not working. Here is the beginning of the function:
function kbdEq () {
$(document).on ('keypress', function (e) {
e.preventDefault();
debugger;
var x = e.charCode || e.keyCode;
// etc.
Jumping into Firebug is straightforward, but trying to test
e.getModifierState('Alt')
(or any other keyboard event as a parameter, with or without quotes) results in this message from Firebug:
e.getModifierState is not a function
I am using Firefox 44.0.2.
What mistake am I (presumably) making here?
As you are using jQuery, note that the event parameter (e in your case) is a jQuery specific object wrapping the actual event object.
To access the original event it has a property originalEvent. So, to access the modifier state you have to write this:
e.originalEvent.getModifierState("Alt");
Note that the jQuery event object has some simpler way to check whether the Alt, Ctrl, Shift or Meta key is pressed. This can be done via e.altKey, e.ctrlKey, e.shiftKey and e.metaKey, respectively.
I have attached a click event listener on an element like:
document.querySelector('.class-name').addEventListener('click', function () {
});
The element may or may not get generated from the server-side.
So, if the server generates the element then all works fine but if not then I get an error like:
Cannot read property 'addEventListener' of null
I know why this happens, but I want to know whether there is a better way of attaching event listeners to elements that won't generate such errors?
There's no way of doing this without some sort of conditional test, but you can save a few characters compared to an if block thus:
var el = document.querySelector('.class-name');
el && el.addEventListener(...);
I don't believe there's any simple way of avoiding the temporary variable (but see below).
NB: the below is included just to show that it's possible and should not be construed as a recommendation ;-)
If this is a very common pattern in your HTML and JS, a way to avoid the temporary assignment to el is this:
var missing = {
addEventListener: function() {};
}; // a "null" element
(document.querySelector('.className') || missing).addEventListener(...);
The idea being that the || missing ensures that there's something present to absorb the addEventListener reference and invocation.
Just check before if your element is here or not (like in comment ) :
var el = document.querySelector('.class-name');
if (el) { el.addEventListener(...); }
Edit : You can also wrap your element .class-name into a div and do something like that :
document.getElementById("myDiv").addEventListener("click",function(e) {
var classes = e.target.className;
if(classes = ".class-name")
//DO SOMETHING
});
Since ES2020
ES2020 introduced optional chaining and that feature is exactly what you need here:
document.querySelector('.class-name')?.addEventListener('click', ()=> console.log("Clicked"));
Supported in all modern up-to-date browsers.
You have to be sure that element exist. So
var element = document.querySelector('.class-name');
if (element)
element.addEventListener('click', function () {});
I'm trying to wean myself off jQuery (my heart is in the right place, no?), and I'm having trouble getting to what would be the equivalent of the :not() selector.
I have document.body.addEventListener("mousewheel", scrollTriggered), which I want to fire on scroll of anything but a specific div (in the fiddle, #something). I've tried integrating event.target, to no avail.
Any help greatly appreciated.
See JSFiddle
You can check whether the event originated from within the element you want to avoid. To do that, you have to traverse up the DOM tree from target and compare each Node's id attribute, or use Node.contains (check the compatibility section first though):
var ignore = document.getElementById('something');
function scrollTriggered(event) {
var target = event.target;
if (target === ignore || ignore.contains(target)) {
return;
}
// do other stuff
}
DEMO
That said, Markasoftware's answer is even better, since it prevents the event in the first place.
The easiest way is probably to set an addEventListener with the third argument to false that does the action, and then have another addEventListener on the element you want to exclude, with a third argument true, which will cancel the event from propagating to the other event listener. The third argument is a little complicated, but the important part is that if it's set to true, that listener will fire before any false handlers. As #FelixKling said, you actually don't need it to be true here, but it's good practice to do it whenever you need a handler to fire before another one, because sometimes it IS needed. Here's a jsfiddle example: http://jsfiddle.net/markasoftware/sBg3a/2/
document.body.addEventListener("mousewheel", scrollTriggered,false);
function scrollTriggered() {
console.log('hi');
}
document.getElementById('something').addEventListener('mousewheel',function(e) {
e.stopPropagation();
}, true);
Although #FelixKling's answer works, I personally think this is more elegant and generally use things like this instead of the other way. I just like how you can have the main event listener just have the listener code, and all the stuff that cancels the event from propagating can be completely separate, making it more unobstrusive
You can check the target element inside your event handler and if that target element has id something return false;
something like this:
function scrollTriggered (event) {
if (event.target.id === "something") {
// don't do anything
return;
} else {
// do something
}
}
You will can use next example code with EcmaScript 6:
function scrollTriggered(event) {
var target = event.target;
if (target.outerHTML.includes('something')) {
return;
}
// do other stuff
}
We extract string from html element and try found in it something. This will work if you located inside necessary element which need ignore.
Programming Question First (from w3 schools)
The programming example way below (from W3 schools) is nice and easy, it works on their website but I'm really confused on something.
onkeypress="return noNumbers(event)"
why is there a return before the function? What does it do? If you know the answer to that - how did you find out that information? My guess would be, that it allows the keypressed function to continue processing the keystroke since my event "interupted" it?
also - I have been trying to see what 'event' is. It doesnt seem to be a keyword. I spent > hour trying to find what it is. It doesnt seem to be assigned anywhere in their code example. Normally in that spot you would see 'this'. If it's a not assigned variable will it always pass the event handler? Confused...
What I want to do with their function
I want to make a password strength checker AS you type. I was looking at their example so I could figure out how to capture keys (cross browser and minimal IE7). My idea was...
<input type="password" name="pword" maxlength="50" size="50" id="field_pword" onkeyup="PasswordStrength(name, 8, 'relaxed')" onblur="CheckField(name, 8, 1)">
note: Yes, I know it's better to assign event handlers outside of the html but I couldn't see a way to pass variables to it unless it was inline. I'm a novice so I may have overlooked something but... thats why I do it IN the HTML.
also, IS IT BAD how I am passing name? it does send pword to the function but am I doing something wrong there? Should I just make it a constant string? It works as is, but sometimes just because something works... doesn't mean it's correct. :)
onkeyup="PasswordStrength('pword', 8, 'relaxed')" onblur="CheckField('pword', 8, 1)">
My checkfield function works (I use it after every field) I recently added in PasswordStrength. My question is... my new function isn't passing the event hander so how can I check what key is pressed? Can I do this?
onkeyup="PasswordStrength(name, 8, 'relaxed', event)"
or should it read...
onkeyup="return PasswordStrength(name, 8, 'relaxed', event)"
If I can't pass whatever 'event' is that way, inside my function can I accurately get what the key pressed was without a big mess of code? Since I'm learning I need examples to be as simple as possible (please).
Using my function I was going to do it this way but I still don't know how to get what key was pressed...
function PasswordStrength(sField, iMinLength, sStrength, e?)
{
var form = document.forms[0];
var gc = form[sField].value;
// once I have the value I can do checking but it would be nice to have WHAT key
// was pressed
// the e? above is where I was thinking of passing the event
W3 example I was pulling some knowledge from...
function noNumbers(e)
{
var keynum;
var keychar;
var numcheck;
if(window.event) // IE
{
keynum = e.keyCode;
}
else if(e.which) // Netscape/Firefox/Opera
{
keynum = e.which;
}
keychar = String.fromCharCode(keynum);
numcheck = /\d/;
return !numcheck.test(keychar);
}
</script>
<form>
Type some text (numbers not allowed):
<input type="text" onkeypress="return noNumbers(event)" />
</form>
</body>
</html>
As someone is typing I was going to change the text using innerHTML beside the password field to say, "Weak", "Ok", "Good", "Perfect" or something along those lines for the password status. I'd love to do it how google does it with a graphic to the left of the field but I don't know how to do that simply. lol.
Is my way fixable? Do you have a better way to do this that I don't know about? Much appreciated. Awaiting an infusion of wisdom...
Just to your first programming questions:
Your suggestion is right, to return a value inside of an event
lets you interrupt the action depending on the values content. Returning false inside onclick
will end in the click not to be done. So <a href="http://test.de"
onclick="return false;">linkname</a> wont link you to anything if
JavaScript is active.
event is simply a variable declared before it runs into the actual event, further explanation below.
You know the elements eventhandler attributes in JavaScript?
They are functions i.e.
document.createElement('div').onclick = function( event ){
//do something...
return true || false;
};
if you assign an onclick attribute to a tag it's simply another adjusted way to create this anonymous function. So
<input onclick="this.value = 'can\'t click me :P Mouse X: ' + event.clientX; return false;" type="text" id="ip" />
will behave as if you created an anonymous function taking the argument event.
window.onload = function(){
document.getElementById('ip').onclick = function( event ){
this.value = 'can\'t click me :P Mouse X: ' + event.clientX; return false;
};
};
This will behave exactly equal except of the delayed assignment.
The this keyword is always the owner object whose property function you're accessing or the object you're passing to an apply/call method. In this case it's obviously the owner - the DOM element. So this.value is the inputs value.
The event passed to the function is just an object containing some useful information about the current browsers state and miscellaneous. It's having slightly different properties filled with different values in different browsers but the main functionality is the same everywhere.
As explained above it makes no difference whether you write what you did or this:
window.onload = function(){
var yourElement = document.getElementsByTagName('pword')[0];
yourElement.onkeyup = function( event ){
PasswordStrength(this.name, 8, 'relaxed')
};
};
No it's not really bad to use just name.. whenever you access a property of the owners object you can omit the this keyword. Thus it's simply the same conflict as the one about writing
<script type="text/javascript">//<![CDATA[
onload = function(){ alert('hello!') };
//]]></script>
instead of window.onload or this.onload or even this.window.onload (which are all theoretically working since the everything containing object has a property named window which refers to itself). You could say it's a matter of convention. But since the convention to always access own properties over the this keyword (except for window which you should access over its property window) is strongly established and supported, you probably should write this.name.
That depends on whether you want to eventually interrupt the event and don't let the user finish his keyup. Explained above.
Why shouldn't you be able to pass the event object? Just treat it like a normal variable.
Combining the information above and the example in your question you should be able to get knowledge about which key was pressed.
1) The "return" word makes it so that if the function returns false, that gets passed back to the event and stops the keystroke from being processed by the browser (and appearing in the input field if that's what the event is on).
2) event is the Event object, which contains information on the event such as what key wa pressed, where the event was fired, etc.
3) Yes, it is bad how you are passing name, because you aren't passing it. Use this.name instead.
4) In this case, you don't need return because you aren't trying to stop a keystroke from being added to the textbox. Similarly, you don't need to pass event because you can pass this.value to get the contents of the textbox.
5) You can just pass this instead of this.name, this.value or whatever other values.Then, in the function, get the properties from the single argument.
6) Once you pass the entire value with this.value, you can run your tests on that. There is absolutely no need to know what key was pressed, especially as things like Ctrl+V would completely screw you over.
7) You can have a <div> and change its width and/or background colour to make a sort of strength bar indicator.