jQuery prevent keyboard press from working if target is undefined? - javascript

I have a ruby on rails application where the user can go to a previous or next question using their keyboard. One page is loaded at a time, which contains the link to a previous page, and the next page.
What I want to do is that if the user is at the very first page, pressing the left keyboard arrow key should not work at all, since it will be undefined. Additionally, if the user is at the very last page, pressing the right keyboard arrow key should not work either, since the next page will be undefined. Right now, if the user is at the first or last page and presses the left or right arrow key respectively, it throws an error in my application saying that "undefined" url can not be found.
I got the prev/next functionality working, but now am confused on how to proceed.
$(function() {
$(document).keyup(function(e) {
switch(e.keyCode) {
case 37 :
var a_href = $(this).find('a.previous_page').attr('href');
window.location=a_href;
break;
case 39 :
//window.location="/page-link-next";
var a_href = $(this).find('a.next_page').attr('href');
window.location=a_href;
break;
}
});
});

Use .length on a jQuery collection (such as .find) to figure out how many elements are in the collection.
Another thing to keep in mind is that var gets hoisted; having two vars declaring the same variable name inside a function isn't exactly valid. Better to declare the variable name elsewhere (such as at the top) and reassign, or use something other than a switch statement so you can use const, which has block scope and is a lot easier to deal with:
$(function() {
$(document).keyup(function(e) {
const keyCode = e.keyCode;
if (keyCode === 37) {
const a = $(this).find('a.previous_page');
if (a.length === 0) return;
window.location= a.attr('href');
} else if (keyCode === 39) {
const a = $(this).find('a.next_page');
if (a.length === 0) return;
window.location= a.attr('href');
}
});
});
It's better not to use switch if you can avoid it - it's unnecessarily wordy and error-prone.

Related

Problem with an event registering multiple times

Currently I have it set to "if true == true" just to simplify because the problem isn't there.
switchBoxes(player){
if (true == true){
document.addEventListener("keypress", function switchListen(event) {
if (event.keyCode == 101) {
console.log("TrapActivated");
}
}, {once:true});
}
}
I have a problem in my game that I am making in javascript where I see "TrapActivated" hundreds of times in the console when I only press the key 'E' once. switchBoxes is a function in a class called collisionObjects. It is meant to create a box that acts as a switch and effects some other part of the map I created when you press the key 'E'. The player is able to move around the map freely around the canvas. Instead of "if true == true", I had collision detection for the player to see if he was touching the switch. The parameter 'player' is so that you can choose who is able to use that switch. When I press 'E', the console gives me anywhere from around 34 to 500 messages. It stops very soon after I have pressed 'E', around 100-200 milliseconds later. And I haven't done anything with the framerate, so it should be whatever the default is.
This is my first question on this site so please forgive me if it is not as specific as it should be.
First of all, use event.key instead of event.keyCode;
Second - Your switchBoxes() function create new listener on every call;
So it's absolutely correct behaviour. For avoid this You can try to use removeEventListener. But, in My opinion, the best way in this case - declarate switchListen in parent scope. Something like:
function switchListen(event) {
if (event.key === 'e') {
console.log("TrapActivated");
}
}
function switchBoxes(player){
if (true == true){
document.addEventListener('keypress', switchListen, {once:true});
}
}
So, You'll create the only one listener, that will be removed at first call because of once:true;

Why wont this event listener work for multiple keys when in an array in javascript?

First code--> My first example does not work, and I am not sure why. I would say a condition, like if(keys[38]) where 38 in the example would be the event.keyCode. If true, it should execute the if statement.
second code--> The second example only works when there is one key being pushed, and I am not sure why it does not work for multiple keys, either. For multiple keys I would say something like if(keys[38] && keys[40]), but that will not work, it should be noted, however, that it would work for just one key, like just if(keys[38]).
I know that there are other ways to get this to work, but my objective is to figure out why these code pieces do not work.
first code piece:
var keys = [];
addEventListener("keydown", function(event) {
keys[event.keyCode] = event.type == "keydown";
event.preventDefault();
});
/*conditions*/
second code piece:
var keys = [];
addEventListener("keydown", function(event) {
keys[event.keyCode] = event.type == "keydown";
event.preventDefault();
/* conditions with multiple keys accessing by if(keys[38] && keys[40]*/
});
thanks ahead of time :)
When you press multiple keys, your addEventListener no longer listens to your first keypress. That's why your if statement is failing. You can test that out on the first example on http://api.jquery.com/event.which/ Try holding one key, then holding a second key, and then releasing the second key. You'll notice that the first key won't be logged anymore.
*edit: A way around that would be to implement it like this:
var keys = {};
$(document).keydown(function (e) {
keys[e.which] = true;
});
$(document).keyup(function (e) {
delete keys[e.which];
});
The difference is that in this case, nothing is getting overwritten, where as in your example your first key press is getting overwritten (and no longer saved) by the second key press.

How can I catch 2+ key presses at once?

Well lately i got interested in creating JS games. (not an area i have experience with but it interests me).
i know there are several gaming engines for JS out there but i dont really want to create a game. rather i am curious on how things work / how can i create one.
I have several questions:
Anyone with suggestions on where can I read about it? Prerequisite (what knowledge is needed).
I tried making a small game of something walking in a rectangular. By binding keyup to the window and checking the event.which to get the key that was pressed. I realized that if i clicked on 2 buttons same time only 1 of them is being registered. how can i overcome that?
$(window).keyup(function(event){
globalEvent = event.which;
});
To directly answer your second question.
Here is one way:
var keyPressed = {};
$(window).keydown(function(e) {
keyPressed[e.which] = true;
}).keyup(function(e) {
keyPressed[e.which] = false;
});
Now you can use keyPressed whenever you want to determine if a key is down:
// wherever
var key1 = 65, key2 = 66; // A and B
if (keyPressed[key1] && keyPressed[key2]) {
// A and B are both being pressed.
}
In order to detect multiple keys being held down, use the keydown and keyup events.
var keys = {};
$(document).keydown(function (e) {
keys[e.which] = true;
});
$(document).keyup(function (e) {
delete keys[e.which];
});

Is it possible to have multiple simultaneous key inputs with ProcessingJS?

I'm working on an RTS style webapp in processingJS, meaning that there is a little minimap that represents a larger map, which the user can only see a small part of at any given moment. I just added the ability to use arrow keys to navigate the map, i.e.:
void keyPressed(){
if(key == CODED){
switch(keyCode){
case(UP): //go up
case(DOWN): //go down , etc
However, I'd like to be able to let a user move diagonally by pressing a combination of two arrow keys. Right now, it seems like this is impossible to do, seeing as how "keyCode" can only seem to hold one value at a time.
Does anybody know any workarounds to this issue?
Best,Sami
As #Xenethyl pointed to in his link in the comments, one way to get around this is by keeping tracks of when a key is pressed and then watching for when the key is released. It is safe to assume that a key is held down in the period of time in between those two events.
I would just do the following in javascript:
document.onkeydown = keydown;
function keydown(evt) {
if (!evt) evt = event;
if (evt.ctrlKey && evt.altKey && evt.keyCode==115) {
alert("CTRL+ALT+F4"); }
else if (evt.shiftKey && evt.keyCode == 9) {
alert("Shift+TAB"); }
}
I haven't tested this - but have you tried:
void keyPressed(){
if(key == 'a' && key == 'b'){
println("this just happened");
}
}
If this works you can find the ascii values for the arrow keys instead of using key CODED.

Purely as an experiment, I am trying to make it absolutely impossible to do anything but enter more data into an input field; feasible?

I've come very close, I think, but can't seem to cover every single one of the fronts listed below:
disable use of backspace, delete, left arrow key, home key, and ctrl for various reasons (all of which prove difficult once you factor in the confusion caused by holding down two at the same time)
make certain that the user cannot exit the field and then re-enter in a loation other than the end (onfocus and onclick attributes cover this)
the toughy: remember the value every time a character is successfully added such that if the user decides to modify the value with JavaScript code injected via the location bar, the original data can be restored
Seeing as how there'd be very little (zero, to be honest) practical use for this, I'm merely pursuing it as a demonstration of knowledge. Alas, it seems I haven't enough; nonetheless, here's the code I'm presently working with for reference:
<input id="test" />
<script>
var d = '', kd = 0;
cancel = function(event)
{
event.target.value = '';
event.target.value = d;
};
handle_up = function(event)
{
if (event.keyCode == 36 || event.keyCode == 37) // home, left
{
kd = 0;
cancel(event);
event.target.value = d;
}
if (event.keyCode != 8 && event.keyCode != 46) // backspace and delete
d = event.target.value;
else // backspace
event.target.value = d; // set to stored ("cached") value
};
handle_down = function(event)
{
if (kd == 1)
{
cancel(event);
return false;
}
if (event.keyCode == 36 || event.keyCode == 37)
{
kd = 1;
cancel(event);
}
if (event.keyCode == 8 || event.keyCode == 46)
{
kd = 1;
cancel(event);
}
};
HTMLElement.prototype.perma = function()
{
this.setAttribute('onfocus', 'cancel(event)');
this.setAttribute('onclick', 'cancel(event)');
this.setAttribute('onkeyup', 'handle_up(event)');
this.setAttribute('onkeydown', 'handle_down(event)');
};
$('#test').perma();
</script>
Again, even though it'd just be for the sake of novelty, I think it'd be really cool to see the cleverness required to get an input box to deny any action but data entry.
BTW since this is for fun. Have you tried to do a whitelist of what you can enter instead of a blacklist of what you can't do.
How about checking the inputted data, running a comparison on the new input, and refusing anything that isn't an extension of what was already there? A little lengthy, perhaps, especially as the field becomes longer, but effective?
Another thing to consider, is that validation schemes - such as the one you describe - should not take place purely on the client side.
If javascript is disabled, for example, it is possible for somebody to submit unvalidated data. If this occurs, the server side code will use it and the condition that you are testing for will go unnoticed.
Always backup client side validation with the same validation on the server.

Categories