My code (seen below) seems to work properly, however, I have been reading (e.g. in How can I avoid autorepeated keydown events in JavaScript?) that in some instances, onkeydown() method needs to be nulled. Why is this?
The intent of this code is to listen for a left or right arrow press (on the index file) and send a function to an iframe, which then forwards another function to another embedded iframe. There was probably a better way to do this, any input?
//Arrow key functionality
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '39') {
// right arrow
document.getElementById('CENTER').contentWindow.fwdFrame();
}
else if (e.keyCode == '37') {
// left arrow
document.getElementById('CENTER').contentWindow.bkFrame();
}
}
The iframe ('CENTER') has the following code:
//Arrow Key Functionality - Forwarded from Index
function fwdFrame() {
document.getElementById('CONTROL').contentWindow.GoNext();
}
function bkFrame() {
document.getElementById('CONTROL').contentWindow.GoBack();
}
Any help appreciated!
Related
I have a game I made with HTML5, CSS, and JavaScript. I have HTML image tags of joystick arrows. I would like users to be able to click my joystick arrow images with the mouse and have it work as if the arrows on the keyboard were pressed. How do I make keyCode 39 fire when the image of the right arrow is clicked? I wrote the code like this but it doesn't work:
var $rt_arrow = $('.rt_arrow')
$rt_arrow.on('click' , function (e) {
e.keyCode == 39
})
You are facing an XY problem.
You don't want to trigger a keyboard event in this case, you just want your mouse event to trigger the same action as your keyboard event.
That is make you code more modular and create functions for each actions, then you can make your handlers call the required function:
onkeydown = e => {
if(e.key === 'ArrowLeft') goLeft();
else if(e.key === 'ArrowRight') goRight();
// ...
};
onclick = e => {
if(e.target === left_arrow) goLeft();
else if(e.target === right_arrow) goRight();
// ...
};
I believe this is what you're looking for http://www.port135.com/2017/12/24/how-to-simulate-keyboard-key-press-in-javascript-using-jquery/
I haven't tested this so I'm not 100% sure, though it seems pretty straight-forward.
So instead of:
e.keyCode == 39
Put:
jQuery.event.trigger({ type: 'keydown', which: 39 });
So the problem is... It doesn't work. And more correctly... how can i better execute those nested ifs?
document.body.onkeypress = function(e) {
e = e || window.event;
if (e.keyCode == '38') { //arrow up
}
if (e.keyCode == '40') { //arrow down
if (top == 1) {
window.setTimeout(show2, 100);
alert('2 layer works');
}
if (top == 2) {
window.setTimeout(show3, 100);
}
if (top == 3) {
window.setTimeout(show4, 100);
}
}
}
I've tried everything. Please help me...
Start with this example. It shows how to hook up the keydown event to the document body correctly. From here you should be able to modify it to add the additional logic you have in your example. Be careful to make sure external variables like top are set correctly.
function handleKeyDown(e) {
console.log('got keyDown event. e.keyCode =', e.keyCode)
}
document.body.addEventListener("keydown", handleKeyDown, false);
<p>Press a key</p>
Where do you change the top value...? Also the first if statement, if its blank like you showed us here, will throw in an error, or at least won't do anything. Why do you say e = e || window.event ..? Also, this might be just me, but don't call the functions like that. Better ( again, at least in my opinion ) to do:
document.body.addEventListener("keypress", e => {
// Get rid of that e = e || window.event, I have no clue why you'd do that.
if (e.keyCode == 38) {
// Actually give it some parameters to do here, leaving it empty will either
// throw an error or in "best" case won't do anything.
}
if (e.keyCode == 40) {
// Again, you said you did var top = 1. It will work here.
if (top == 1) {
window.setTimeout(show2, 100);
alert('2 layer works');
}
// But you dont INCREMENT the top variable anywhere, so this wont work.
if (top == 2) {
window.setTimeout(show3, 100);
}
// But you dont INCREMENT the top variable anywhere, so this wont work.
if (top == 3) {
window.setTimeout(show4, 100);
}
}
})
This question is really, really badly formatted and you haven't provided much information. Show us the error you get, use console.log all the time, it's your best friend.
In an Aurelia viewmodel component, I have the following JQuery code that works to capture Ctrl+S or Ctrl+Enter while a modal is visible and call the save function:
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
}
}
});
However, I foresee adding a similar function to 40+ viewmodels, and that doesn't seem very DRY and adds some ugly code to each of my viewmodels. I would like to create a generic addEventListener function in a singleton class to easily call from each of my views. Here's what I have in mind:
addListenerSave(visible, callback) {
// Add an event listener to redirect keyboard shortcuts to specific actions
console.log("addListenerSave()");
$(window).bind('keydown', function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.which == 83) || (event.which == 115) || (event.which == 10) || (event.which == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
event.preventDefault();
if ($(visible).is(':visible')) {
console.log("Keyboard shortcut: Save");
callback();
}
}
}
});
}
Then, in my individual components, I should only need the following code on instantiation (in the attached() component life cycle):
this.config.addListenerSave(this.edit_calendar, this.saveCalendar);
However, this does not work. saveCalendar() is called but maybe from another scope/context, so I get an error inside saveCalendar that says:
"Cannot read property 'selectedId' of undefined".
This is referring to the saveCalendar() code if (this.selectedId).... What am I doing wrong?
Finally, should I also be removing this event listener when my Aurelia component is detached? How?
One alternate idea I had was to use Aurelia's eventAggregator to create a global event listener that always is listening for Ctrl+S or Ctrl+Enter and then publishing a message that can be subscribed in each component.
To answer your original question, you're on the right track - but due to the semantics of this in JavaScript, you'll need to bind your function. (If you're coming from a C# perspective, it may help to think that all functions in JavaScript are essentially extension methods; as such, passing functions can be VERY powerful.) It's easy to miss this because of the new ES6 class syntax.
This should work to mitigate your issue:
this.config.addListenerSave(this.edit_calendar, this.saveCalendar.bind(this));
That said, your solution using Aurelia's Event Aggregator is a much better fit for your use case and much more scalable. I thought I'd post this answer to address the original issue, which was simply a matter of function scope.
I successfully implemented the alternate solution of adding a global event listener that uses Aurelia's EventAggregator to share Ctrl+S/Ctrl+Enter. Original question still stands but perhaps it wasn't the best approach anyway. Here's my solution:
config.js (global singleton class)
#inject(EventAggregator)
export class Config {
constructor(eventAggregator) {
var self = this;
this.eventAggregator = eventAggregator;
// listen for Ctrl+S or Ctrl+Enter and publish event
window.addEventListener("keydown", function(event) {
if (event.ctrlKey || event.metaKey) { // Ctrl + ___
if ((event.keyCode == 83) || (event.keyCode == 115) || (event.keyCode == 10) || (event.keyCode == 13)) { // Ctrl+Enter or Ctrl+S
// Save button
console.log("Publishing ewKeyboardShortcutSave...");
event.preventDefault();
self.eventAggregator.publish('ewKeyboardShortcutSave', true);
}
}
});
}
}
Then, inside my component viewmodel calendar.js:
#inject(EventAggregator)
export class Calendar {
constructor(eventAggregator) {
this.eventAggregator = eventAggregator;
}
attached() {
var self = this;
// Ctrl+Enter is save
this.eventAggregator.subscribe('ewKeyboardShortcutSave', response => {
console.log("I heard ewKeyboardShortcutSave: " + response);
if ($(self.edit_calendar).is(':visible')) {
self.saveCalendar();
}
});
}
}
Works like a charm, and now I can freely add more component event listeners and even extend the functionality to add a global listener for Ctrl+F (for find), etc.
I have a problem with javascript keys, Chrome (only testing on chrome right now) does not recognise up and down arrows on text input, as it has this default behaviour in which it changes the caret position.
My code is as follows:
if (!e) e = window.event;
var keyCode = e.keyCode || e.which;
if (keyCode == '13'){ //enter key
//some code that works
return false;
}else if(keyCode=='38'){ //up key
//some other code that doesn't work
return false;
}else if(keyCode=='40'){ //down key
//some other code that doesn't work
return false;
}
If anyone has a solution I will greatly appreciate it.
Thank you!
Hard to see where the code is from (an keypress listener I guess).
As you can see below and this fiddle (and as Teemu also pointed out), keypress won't get called on arrow keys.
On another note, use event.preventDefault() to prevent the default behaviour of the browser, in your case the placing of the caret, also your listener functions can except an event object as a parameter.
var listener = function (e) {
e = e || window.event;
alert(e.type);
var keyCode = e.keyCode || e.which;
if(keyCode=='38' || keyCode=='40'){ //arrow key
alert("arrow!");
e.preventDefault();
return false;
}
}
var elem = document.getElementById('input');
elem.addEventListener('keydown', listener, false);
ok... I might be a lazy one to search but it is a bit annoying that all I can find is
"how can i set scroll down event" when I searched "how do i prevent scroll down".
in my javascript code, I set event for down arrow key. When I press down arrow
from the browser, the browser not only does an event I set, but also does
scrolling down the page which is not I intended to. So here is my question.
How can I disable scroll down function which occurs when I press down arrow?
any help will be appreciated.
If you want to prevent the vertical scrollbar and any vertical scrolling action by the user, you can use this javascript:
document.body.style.overflowY = "hidden";
Or, this can also be set with a CSS rule:
body {overflow-y: hidden;}
On the other hand, if what you're trying to do is to prevent the default key handler for the down arrow from doing anything after you process the down array, then you need to call e.preventDefault() like this:
function myKeyDownHandler(e) {
// your code here
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false; // older versions of IE (yuck)
}
return false;
}
A cleaner way if you need to do this in more than one place would be to make your own cross browser function for this:
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false; // older versions of IE (yuck)
}
}
function myKeyDownHandler(e) {
// your code here
preventDefault(e);
return false;
}
This is one of those perfect examples where a cross-browser framework (jQuery/YUI/etc) saves you time because they've already done all this cross-browser work for you.
Here's an interesting article on preventDefault and stopPropagation().
Here is an example page that doesn't allow for the use of the arrow keys for scrolling:
<script>
document.onkeydown = function(evt) {
evt = evt || window.event;
var keyCode = evt.keyCode;
if (keyCode >= 37 && keyCode <= 40) {
return false;
}
};
</script>
<body style="height:3000px;">
</body>