I'm implementing a couple of shortcut keys for my MVC web app and I'm running into an issue. The app allows users to answer multiple choice or short answer questions, and I'd like to make multiple choice questions answerable by just pressing 1,2,3,4 etc. Here's what I have right now:
$(document).on("keypress", function (e) {
self.someKeyPressed(e);
});
[...]
someKeyPressed: function(e) {
// locate all the multiple choice buttons in this view
var buttons = this.$el.find('button');
if(_.contains(_.range(49,55), e.which) && buttons.length) {
index = e.which - 49;
var answer = $(buttons[index]).text();
this.answerQuestion(answer);
}
e.stopPropagation();
},
This works fine, except for the case when a multiple-choice question is immediately followed up by a short answer question. In this case, the same <div> used to contain the elements, is instead replaced with:
<input placeholder="answer goes here" autofocus="autofocus">
And here's where the problem is: whatever shortcut I used on my keyboard to answer the multiple choice question shows up in the as if the user had typed it in, even though that view didn't exist at the time of the keypress. I tried to wire up an event on "input keypress" and that doesn't even go off in this situation. Interestingly enough, removing autofocus fixes the issue, but unfortunately I need it for for the user experience to be pleasant.
What's going on here? Is there anything I can do to prevent the keypress from making it into the input until I'm ready?
Edit: it looks like adding e.preventDefault() right after e.stopPropagation() did the trick. Without it, the shortcut number would be typed into the input as soon as the jquery event dispatcher logic completed, but no sooner.
It looks like calling e.preventDefault() does the trick, even though I'd still love to find out one day why exactly this makes a difference.
Related
I have this code that fills and focuses but I need to add an arrow down event as it will trigger list popup like pictured below. Can anyone help me with the line?
document.body.appendChild(element)
element.addEventListener('click', function(){
document.querySelector("input#generic_test_order_search.ui-autocomplete-input").value = '16048'
document.querySelector("input#generic_test_order_search.ui-autocomplete-input").focus()
})
})();
You can use the KeyboardEvent API. Use the keyup or keydown event - depending on which one suits you better, and look up the keycode (the arrow down keycode is 40). When the key is pressed, the event will trigger. You can use the website to check which keycode is linked to which key on the keyboard by clicking here.
I got the code below from the MDN web docs.
eventTarget.addEventListener("keyup", event => {
if (event.isComposing || event.keyCode === 229) {
return;
}
// do something
});
Not enough information. It might be better to provide full HTML...
(A bit connected question: Script to fill a value automatically in the webpage input box)
1 - The goal here is to get class of the suggestion dropmenu. And find children inside, and maybe another children inside, and then trigger click() on it.
Since it is pretty hard to guess the class names and the structure, here is a pretty much equal example of how to click on drop-down suggestion.
a) Here is Wikipedia. Open the link.
https://en.wikipedia.org/wiki/Stack_Exchange
b) Save the following code as a bookmarklet:
javascript:(function(){
document.getElementsByClassName('suggestions')[0].children[0].children[1].click();
})();
c) Then write three letters goo to the search in Wikipedia.
d) And finally trigger the bookmarklet. Then it will open up the second suggested link: children[1]. This is how it may work. You might try like this with your HTML on your own.
2 - There is a chance that making a bookmarklet might be a slightly better than appending an event listener, since all you need is to insert values.
Another option is Tampermonkey / Greasemonkey to trigger things even more automatically (in fact, this option is pretty much the same as a bookmarklet, and the code structure is absolutely the same and fully compatible).
I am making a chrome extension that occasionally prevents all keyboard inputs from reaching the webpage temporarily (as the extension's handler performs its own tasks with the keyboard inputs that it catches). And the extension does a good job listening to all of those inputs.
HOWEVER, some keyboard inputs still get through the webpage! Specifically, certain keyboard inputs that use the Alt modifier key reach the webpage. I have replicated the issue with this code:
$(window).get(0).addEventListener("keypress",
function(e){
e.stopPropagation();
e.preventDefault();
}, true);
You can interact with the code in this jsfiddle: https://jsfiddle.net/Sophtware/5ucefew2/
Can someone help me figure out why this is happening and how to fix it?
EDIT #1: I found out that the symbols that are coming through the preventDefault call are things like accents or other "combining characters" (like ´, ˆ, ¨). In fact, once a combining character has been typed, the next character typed will always also fail to be blocked.
Well, first, you didn't have jQuery loaded in your Fiddle.
Second, you need to use the keydown event, not keypress because keypress doesn't fire when keys that don't produce visible characters are pressed. This is why you found that some characters work with it and others don't.
Third, your event binding code isn't really written correctly. There is no need to use get(0) when jQuery returns a wrapped set that contains only one item. And since there is only one window or document, that code isn't needed.
Additionally, you can check explicitly for the ALT key being pressed.
Lastly, please don't post your code to 3rd party sites because those links can become broken over time. Instead post your code snippets right here.
See comments inline:
// Set the event on the document, but then test for the input element when it happens
$(document).on("keydown", "input[type='text']", function(e){
// Check the event for the ALT key press
console.log("Keystroke cancelled!");
e.preventDefault();
e.stopPropagation();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>
Type in Alt + 'e', Alt + 'i', or other Alt combinations! They get typed in even though they're not supposed to!
</h3>
<p>
Strangely, Alt+j and Alt+k cannot be written more than once in a row and act strange in general.
If you type in Alt + e and then a regular letter key press, the letter gets typed! ??????
</p>
<input type="text">
I have seen multiple solutions and have tried them all, but none of them seem to be working for what I am trying to do.
Here is how I'm sending the key-presses right now:
$("#choice").autotype(text + "{{enter}}", {delay: 100});
It works (as in, it shows the letters in the textbox) but I still need to press enter manually, despite it being part of the line of code above.
I have also attempted using the code I found from another stackoverflow answer:
e = jQuery.Event("keypress")
e.which = 13 //choose the one you want
$("#test").keypress(function(){
alert('keypress triggered')
}).trigger(e)
(That's the raw version, I changed it a bit to fit my needs but it basically was the same).
I've done a lot of research on this but I can't figure out how to make a true keystroke... is it even possible?
For reference, the keystroke that I'm trying to automate is the enter (return) key.
Thanks.
We've got some code like this that has been working for some time. It's for a button that submits an html form, unless a nearby textbox is empty. I've taken this snippet directly from our code; I've changed the contents of the fields, but haven't deleted anything.
<input
type="image"
name="inputName"
id="inputId"
src="someImage"
alt="altText"
onclick="
javascript:var obj = document.all ? document.all["aTextInputFormFieldId"] :
document.getElementById("aTextInputFormFieldId");
if(obj.value.length == 0)
{
alert('It is 0!');
return false;
};"
style="someStyle" />
(The original code is all on one line, but linebreaks have been added here for clarity).
It seems to work perfectly in Firefox. But in IE, it fails in a way that I can't understand: if the input field (aTextInputFormFieldId) is empty, it puts up the alert, but then submits the form anyway after the user clicks the okay button on the alert.
When I did a view source on the entire page, and copied it locally, it seems to work perfectly; it either submits the form, or puts up the alert, and then refuses to submit.
My best current (but still lousy) theory is that one of the included JavaScript libraries is doing something funny, which would explain why it failed on the real site, but fails when I copy it locally (since I didn't grab the various libraries it's importing.) This makes logical sense, and I'll check it out by grabbing the libraries too, but I'm having a hard time imagining what these libraries could be doing to mess this up (or why)...they're just normal utility libraries like jquery, utility functions, etc.
So does anyone have a theory about what could be happening here?
You mentioned jQuery, jQuery can interfere with your form if it is doing anything through its submit() handler. Check to see if jQuery.submit() is bound to your form.
Usually when doing pure javascript it is not enough to return false. Depending on what you want to accomplish you might want to look at preventDefault or stopPropagation
When working with Internet Explorer be aware that the event object is not passed to the function but can be found in window.event instead.
Update
Internet explorer might want you to use event.returnValue = false; instead. In your case that would be window.event.returnValue = false; when targeting IE.
Good luck
Javascript protocol links have to be one line, ie. no new lines.
onclick="javascript:var obj = document.all ? document.all["aTextInputFormFieldId"] :document.getElementById("aTextInputFormFieldId"); if(obj.value.length == 0){alert('It is 0!'); return false;};"
I have a form and it has 4 input elements. if the user enters just two entries and clicks anywhere on the screen (out the form)...i would like to save the details..it is like auto-save.
I have id of my form..i want to compare with form id of the current control on the screen..so that i can ssave the data if both form ids are different..
could you please tell me how can i get the form id of current control location on screen (some times the control could be outside the forms..in that case form id of current cotrol location would null)... but how can i determine that in javascript.
please suggest...
Many Thanks in advance,
Jack.
That's an interesting question.
Well, if you didn't think a second (as I admittedly did), you would just hook on the blur event of the HTML <form> element in question.
<form onblur="autosave(this)">
However, the HTML <form> element doesn't support that event. Too bad.
I then thought about jQuery's new 1.4 focusout() event.
$('form').focusout(function() { autosave(this); });
Unfortunately that event get fired as well when you just jump (tab, click) to the next input field inside the same form. Not so nice, it'll probably be too expensive to autosave on every fieldjump. The same effect as with an $(':input').blur(function() { autosave(this.form); });.
I then tried the other way round using focusin():
$('form').focusin(function() {
$(this).addClass('focused');
});
$(':not(form)').focusin(function(e) {
if (!$(e.target).parents('form.focused').length) {
var form = $('form.focused').removeClass('focused');
autosave(form);
}
});
Strangely enough this works in IE only and not in the other browsers. It'll be another IE bug/quirk that focus is supported by all elements other than input elements.
Your best bet will probably be hooking on the click() event instead.
$('form').focusin(function() {
$(this).addClass('focused');
});
$(':not(form)').click(function(e) {
if (!$(e.target).parents('form.focused').length) {
var form = $('form.focused').removeClass('focused');
autosave(form);
}
});
This works fine. You can find here a live demo.
Note that I don't mean to push you jQuery (a JS library which insanely eases HTML DOM traversion and manipulation) through your throat or so, but I don't see nice ways in plain JavaScript to achieve this without writing 10 times as much as code here.