I have a search field that takes user input and makes ajax requests using a debounced event listener.
html:
<input id="search" type="text"></input>
javascript:
function makeRequest() {
// make ajax request, do things with the information
}
$('#search').on('keypress', _.debounce(makeRequest, 200));
I need the event listener to not use the debounced ajax function on arrow up and down, that is event.keyCode === 38 or event.keyCode === 40
Is there a way to apply the advice from this question to my problem?
Make sure you save the results and only call the function, creating the function on every keypress creates an unnecessary overhead.
var debounced = _.debounce(makeRequest, 200);
$('#search').on('keypress', function(event) {
// just exit if it's an up or down arrow
if (event.which === 38 || event.which === 40) return;
debounced();
});
You just need to handle the keypress event in a different manner, where you can see the event properties.
Try this instead...
$('#search').on('keypress', function(event) {
// just exit if it's an up or down arrow
if (event.which === 38 || event.which === 40) return;
// do whatever you want here, knowing that up or down was not pressed.
});
Since your question is not about the debounce method you are trying to use, I've removed that from my example so you can focus on the specific issue that you are asking about.
The problem was that the callback to the event listener needs to call the function returned from _.debounce, not just create the debounced function.
$('#search').on('keypress', function(event) {
if (event.which === 38 || event.which === 40) {
// do other things
return;
}
_.debounce(makeRequest, 200)();
});
Related
I am trying to create a hangman game, but my event listener doesn't seem as though it's working? When I press a key, there's no response from the webpage.
document.onkeydown = function (event) {
// If the game is finished, one keystroke will reset the game
if (hasFinished) {
resetGame();
hasFinished = false;
console.log("eventListenerWorking16");
} else {
// Make sure A-Z was actually pressed
if (event.keyCode >= 65 && event.keycode <= 90) {
makeGuess(event.key.toLowerCase());
updateDisplay();
checkWin();
checkLoss();
console.log("eventListenerWorking16");
}
}
};
Oh great .. One typo can takes hrs to resolve
One typo in this line
if (event.keyCode >= 65 && event.keycode <= 90) {
It has to be event.keyCode Caps not small
IMHO the event should fire correctly.
I think to make a better debug you should place a console.log right after the anonymous function call (see code below).
This way it will be possible to understand if there is something wrong after (that concerns the logic applied later).
document.onkeydown = function (event) {
console.log("keydown event fired");
// If the game is finished, one keystroke will reset the game
if (hasFinished) {
resetGame();
hasFinished = false;
console.log("eventListenerWorking16 hasFinished");
} else {
// Make sure A-Z was actually pressed
if (event.keyCode >= 65 && event.keycode <= 90) {
makeGuess(event.key.toLowerCase());
updateDisplay();
checkWin();
checkLoss();
console.log("eventListenerWorking16 makeGuess");
}
}
};
Try using this code:
document.addEventListener("keydown", myScript);
I want to capture "enter" and "blur" on a form field. If I hit "enter" and "tab", it will also trigger the blur event... Only one trigger, so "OR" not "AND.
$('#login-input-password').bind('blur keypress', function(e){
if (e.type == 'blur' || e.keyCode == 13) {
// do something only once, not twice
// e.g., if I hit "[enter"] and tab to blur, I don't want it to call twice...
}
});
answer accepted implemented
FUNCTION usage
function bindTriggerEnterOrBlur(selector,myFunction)
{
$(selector).bind('blur keypress', function(e){
if (e.type == 'blur' || e.keyCode == 13) {
if (!$(selector).data('has-triggered')) {
$(selector).data('has-triggered', true);
// do something only once, not twice
myFunction();
// e.g., if I hit "[enter"] and tab to blur, I don't want it to call twice...
}
}
});
$(selector).bind('focus', function(e){
$(selector).data('has-triggered', false);
$(selector).select();
});
}
CALL to FUNCTION
bindTriggerEnterOrBlur('#login-input-email',submitLoginEmail);
Where submitLoginEmail is the function that does something for the trigger, e.g.,
function submitLoginEmail()
{
// submit on enter...
var email = $("#login-input-email").val();
if(validEmail(email))
{
submitNextLogin();
}
}
If I am getting your requirement right, you want to execute the callback only once but currently it is getting executed twice.
If that is the case then you will need some way to indicate if the callback has been called already.
One way would be to use data attributes
$('#login-input-password').bind('blur keypress', function(e){
if (e.type == 'blur' || e.keyCode == 13) {
if (!$(this).data('done') {
$(this).data('done', true);
// do something only once, not twice
// e.g., if I hit "[enter"] and tab to blur, I don't want it to call twice...
}
}
});
You will also need another event handler to reset the done attribute of the element
$('#login-input-password').bind('focus', function(e) {
$(this).data('done', false);
});
You are doing an OR. You want a XOR (Exclusive OR), which has to be done using a combination of comparisons.
if (( (e.type == 'blur') && !(e.keyCode == 13)) ||
(!(e.type == 'blur') && (e.keyCode == 13))) {
// do something only once, not twice
// e.g., if I hit "[enter"] and tab to blur, I don't want it to call twice...
}
You want to prevent the script from firing again though, so you'll need to do even more state comparison to make sure your asynchronous event handler knows that the blur or keypress events have occurred and ensure the handler doesn't run twice.
You can also do something like:
var doo = function(e){ console.log("do..."); }
$('#wmd-input').bind('blur', doo);
$('#wmd-input').bind('keypress focus', function(e) {
$('#wmd-input').off('blur');
if (e.keyCode == 13) {
doo(e);
} else
$('#wmd-input').bind('blur', doo);
});
And it does bind again when focus happens.
In a jQuery script I have a function that normally gets called in response to a click, so acts as an event handler, but I also need to call it directly. In both cases it needs some parameters.
So, the situation, simplified, is this:
function go(e) {
console.log(e.data.dir)
}
$("body").keydown(function(e) {
if (e.which == 37) { // left
go({dir: 'forward'});
} else if (e.which == 39) { // right
go({dir: 'forward'});
}
});
$('.forward').on('click', {
dir: 'forward'
}, go);
Here's a fiddle
This clearly doesn't work because when I call the function directly there's no data key.
A workaround would be to call the function like this:
go({data: {dir: 'forward'}});
And it works, but is pretty ugly.
What would it be the right approach in such a case?
In this particular case, you can solve the issue with apply() and just pass along the arguments from the event handler if the condition is truthy
function go(e) {
console.log(e.data.dir)
}
$("body").on('keydown', {dir: 'forward'}, function(e) {
if (e.which === 37 || e.which === 39) {
go.apply(this, arguments);
}
});
$('.forward').on('click', {dir: 'forward'}, go);
FIDDLE
Or you could pass in an object with the matching properties
$("body").on('keydown', {dir: 'forward'}, function(e) {
if (e.which === 37 || e.which === 39)
go({data:{dir: 'forward'}});
});
or trigger the click event with a custom event
$("body").on('keydown', {dir: 'forward'}, function(e) {
if (e.which === 37 || e.which === 39)
$('.forward').trigger('click', [{data: {dir: 'forward'}}] );
});
There are two ways I can see this going.
You could store you parameter object in a variable at the top of your script, and pass the variable to go() when you need to call it outside of a click handler. That would make things a little less ugly.
Or you could check if e is null inside go(), and if it is, use/set some generic default.
Either would be acceptable, depending on what all the method has to do.
I think I would do something like this (unless I need the event):
function go(data) {
console.log(data.dir)
}
$("body").keydown(function(e) {
if (e.which == 37) { // left
go({dir: 'forward'});
} else if (e.which == 39) { // right
go({dir: 'forward'});
}
});
$('.forward').on('click', function(){
go({dir: 'forward'});
});
For whatever reason I can't capture "SHIFT+TAB" combination.
I am using the latest jQuery.
Same result if I use other ajax/javascript, etc.
Here is a simple example that should work as I currently understand it...
event.which or event.KeyCode are always "undefined" only shiftKey exists in a scenario involving a "SHIFT+TAB" or backward keyboard traversal, traditionally inherent in windows based apps/web or otherwise...
function ShiftTab()
{
debugger;
if(event.KeyCode == 9 && event.shiftKey) // neither this line nor the following work
// if (event.which == 9 && event.shiftKey) // shift + tab, traverse backwards, using keyboard
{
return true;
}
else
{
return false;
}
}
this seems to be yet another item related to tab order that no longer works as it traditionally worked in Microsoft.Net WinForm/WebForm based apps.
If you are using jQuery, this should be how the code is working. Make sure keyCode is lower case. Also, jQuery normalizes keyCode into which:
$(document).keyup(function (e) {
if (e.which === 9 && e.shiftKey) {
ShiftTab();
}
});
If you're into terse JavaScript:
$(document).keyup(function (e) {
e.which === 9 && e.shiftKey && ShiftTab();
});
jQuery 1.7+ on syntax:
$(document).on('keyup', function (e) {
e.which === 9 && e.shiftKey && ShiftTab();
});
I created a function which I wired up to my button's onkeydown event. I used onkeydown, because onkeypress would not capture my tab key press
function ShiftTab(evt) {
var e = event || evt; // for trans-browser compatibility
var charCode = e.which || e.keyCode; // for trans-browser compatibility
if (charCode === 9) {
if (e.shiftKey) {
$('#controlName').focus();
return false;
} else {
return true;
}
}
I took this approach to deal with two specific problems:
onkeypress would not capture tab key press
When click shift-tab, shift key press would trigger function, so I had nest the shiftkey modifier check
use same code inside keypress event.
the tab changes the element between keypress and keyup.
here we get event.key = tab and event.shiftKey = true.
I know this exact question was asked here, but the answer didn't work for what I needed to do so I figured I'd give some example code and explain a bit...
$(document).keypress(
function (event) {
// Pressing Up or Right: Advance to next video
if (event.keyCode == 40 || event.keyCode == 39) {
event.preventDefault();
$(".current").next().click();
}
// Pressing Down or Left: Back to previous video
else if (event.keyCode == 38 || event.keyCode == 37) {
event.preventDefault();
$(".current").prev().click();
}
}
);
It basically disables the arrow keys to use them for something else, but doing:
$(document).keypress(function () { });
doesn't enable the default function again... I need it to scroll the page without having to create a scroll function for it...
Any ideas?
Thanks,
Matt
Adding a new handler doesn't replace the previous one, it adds a new one. You may be looking for jQuery#unbind if you're trying to remove the previous handler, but if you're going to be turning this on and off a lot, you probably would be better off with a flag telling you whether to prevent the default or not in your existing handler.
Adding, and later removing, a handler looks like this:
function keypressHandler() { /* ... */};
$('#thingy').keypress(keypressHandler);
// ...elsewhere...
$('#thingy').unbind('keypress', keypressHandler);
I'm not sure this is the right way to handle it.
A better way to approach this problem would be to put some kind of check inside your document.keypress instructions.. like..
var enableKeys = false;
$(document).keypress(
function (event) {
// Pressing Up or Right: Advance to next video
if (event.keyCode == 40 || event.keyCode == 39 && enableKeys) {
event.preventDefault();
$(".current").next().click();
}
// Pressing Down or Left: Back to previous video
else if (event.keyCode == 38 || event.keyCode == 37 && enableKeys) {
event.preventDefault();
$(".current").prev().click();
}
}
);
Then control the enablekeys wherever you feel necessary, either with a hover, or something along those lines.
function(e){ e.preventDefault(); }
and its opposite
function(e){ return true; }
Why not just wrap a condition around event.preventDefault(); in your current code?
Try to unbind the keypress event from document.
I don't know of any other ways to do it.
HTH